Web Api found ...
This commit is contained in:
@ -1,12 +1,11 @@
|
|||||||
{
|
{
|
||||||
"projects": [
|
"projects": [
|
||||||
"src",
|
"src",
|
||||||
"scripts",
|
"test"
|
||||||
"tests"
|
|
||||||
],
|
],
|
||||||
"sdk": {
|
"sdk": {
|
||||||
"runtime": "dotnet",
|
"runtime": "dotnet",
|
||||||
"architecture": "x64"
|
"version": "8.0.405"
|
||||||
},
|
},
|
||||||
"packages": "packages"
|
"packages": "packages"
|
||||||
}
|
}
|
||||||
|
@ -1,145 +0,0 @@
|
|||||||
@inherits Microsoft.Extensions.CodeGeneration.Templating.RazorTemplateBase
|
|
||||||
@using Microsoft.Extensions.CodeGeneration.EntityFramework
|
|
||||||
@@model @Model.ViewDataTypeName
|
|
||||||
|
|
||||||
@{
|
|
||||||
if (Model.IsPartialView)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
else if (Model.IsLayoutPageSelected)
|
|
||||||
{
|
|
||||||
@:@@{
|
|
||||||
@:ViewData["Title"] = @@Model.ViewName;
|
|
||||||
if (!string.IsNullOrEmpty(Model.LayoutPageFile))
|
|
||||||
{
|
|
||||||
@:Layout = "@Model.LayoutPageFile";
|
|
||||||
}
|
|
||||||
@:}
|
|
||||||
@:
|
|
||||||
@:<h2>@@Model.ViewName</h2>
|
|
||||||
@:
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
@:@@{
|
|
||||||
@:Layout = "null";
|
|
||||||
@:}
|
|
||||||
@:
|
|
||||||
@:<!DOCTYPE html>
|
|
||||||
@:
|
|
||||||
@:<html>
|
|
||||||
@:<head>
|
|
||||||
@:<meta name="viewport" content="width=device-width" />
|
|
||||||
@:<title>@Model.ViewName</title>
|
|
||||||
@:</head>
|
|
||||||
@:<body>
|
|
||||||
@:
|
|
||||||
// PushIndent(" ");
|
|
||||||
}
|
|
||||||
@:<form asp-action="@Model.ViewName">
|
|
||||||
@:<div class="form-horizontal">
|
|
||||||
@:<h4>@@Model.ViewDataTypeShortName"]</h4>
|
|
||||||
@:<hr />
|
|
||||||
@:<div asp-validation-summary="ModelOnly" class="text-danger"></div>
|
|
||||||
foreach (var property in Model.ModelMetadata.Properties)
|
|
||||||
{
|
|
||||||
if (property.Scaffold && !property.IsAutoGenerated && !property.IsReadOnly)
|
|
||||||
{
|
|
||||||
|
|
||||||
// If the property is a primary key and Guid, then the Guid is generated in the controller. Hence, this propery is not displayed on the view.
|
|
||||||
if (property.IsPrimaryKey)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (property.IsForeignKey)
|
|
||||||
{
|
|
||||||
@:<div class="form-group">
|
|
||||||
@:<label asp-for="@property.PropertyName" class="col-md-2 control-label"></label>
|
|
||||||
@:<div class="col-md-10">
|
|
||||||
@:<select asp-for="@property.PropertyName" class ="form-control"></select>
|
|
||||||
@:</div>
|
|
||||||
@:</div>
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool isCheckbox = property.TypeName.Equals("System.Boolean");
|
|
||||||
if (isCheckbox)
|
|
||||||
{
|
|
||||||
@:<div class="form-group">
|
|
||||||
@:<div class="col-md-offset-2 col-md-10">
|
|
||||||
@:<div class="checkbox">
|
|
||||||
@:<input asp-for="@property.PropertyName" />
|
|
||||||
@:<label asp-for="@property.PropertyName"></label>
|
|
||||||
@:</div>
|
|
||||||
@:</div>
|
|
||||||
@:</div>
|
|
||||||
}
|
|
||||||
else if (property.IsEnum && !property.IsEnumFlags)
|
|
||||||
{
|
|
||||||
@:<div class="form-group">
|
|
||||||
@:<label asp-for="@property.PropertyName" class="col-md-2 control-label"></label>
|
|
||||||
@:<div class="col-md-10">
|
|
||||||
@:<select asp-for="@property.PropertyName" class="form-control"></select>
|
|
||||||
@:<span asp-validation-for="@property.PropertyName" class="text-danger" ></span>
|
|
||||||
@:</div>
|
|
||||||
@:</div>
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
@:<div class="form-group">
|
|
||||||
@:<label asp-for="@property.PropertyName" class="col-md-2 control-label"></label>
|
|
||||||
@:<div class="col-md-10">
|
|
||||||
@:<input asp-for="@property.PropertyName" class="form-control" />
|
|
||||||
@:<span asp-validation-for="@property.PropertyName" class="text-danger" ></span>
|
|
||||||
@:</div>
|
|
||||||
@:</div>
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
<div class="form-group">
|
|
||||||
<div class="col-md-offset-2 col-md-10">
|
|
||||||
<input type="submit" value="Create" class="btn btn-default" />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
|
|
||||||
<div>
|
|
||||||
<a asp-action="Index">@Back to List</a>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
@{
|
|
||||||
if (Model.ReferenceScriptLibraries && (Model.IsLayoutPageSelected || Model.IsPartialView))
|
|
||||||
{
|
|
||||||
@:@@section Scripts {
|
|
||||||
@:<script src="~/lib/jquery/dist/jquery.min.js"></script>
|
|
||||||
@:<script src="~/lib/jquery-validation/dist/jquery.validate.min.js"></script>
|
|
||||||
@:<script src="~/lib/jquery-validation-unobtrusive/jquery.validate.unobtrusive.min.js"></script>
|
|
||||||
@:}
|
|
||||||
}
|
|
||||||
// The following code closes the tag used in the case of a view using a layout page and the body and html tags in the case of a regular view page
|
|
||||||
if (!Model.IsPartialView && !Model.IsLayoutPageSelected)
|
|
||||||
{
|
|
||||||
if (Model.ReferenceScriptLibraries)
|
|
||||||
{
|
|
||||||
@:@@section Scripts {
|
|
||||||
@:<script src="~/lib/jquery/dist/jquery.min.js"></script>
|
|
||||||
@:<script src="~/lib/jquery-validation/dist/jquery.validate.min.js"></script>
|
|
||||||
@:<script src="~/lib/jquery-validation-unobtrusive/jquery.validate.unobtrusive.min.js"></script>
|
|
||||||
@:}
|
|
||||||
//ClearIndent();
|
|
||||||
}
|
|
||||||
@:</body>
|
|
||||||
@:</html>
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@functions
|
|
||||||
{
|
|
||||||
// Do we need to use this in conjunction with the PrimaryKey check?
|
|
||||||
bool IsPropertyGuid(PropertyMetadata property)
|
|
||||||
{
|
|
||||||
return string.Equals("System.Guid", property.TypeName, StringComparison.OrdinalIgnoreCase);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,81 +0,0 @@
|
|||||||
@inherits Microsoft.Extensions.CodeGeneration.Templating.RazorTemplateBase
|
|
||||||
@using Microsoft.Extensions.CodeGeneration.EntityFramework
|
|
||||||
@@model @Model.ViewDataTypeName
|
|
||||||
|
|
||||||
@{
|
|
||||||
if (Model.IsPartialView)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
else if (Model.IsLayoutPageSelected)
|
|
||||||
{
|
|
||||||
@:@@{
|
|
||||||
@:ViewData["Title"] = @@Model.ViewName;
|
|
||||||
if (!string.IsNullOrEmpty(Model.LayoutPageFile))
|
|
||||||
{
|
|
||||||
@:Layout = "@Model.LayoutPageFile";
|
|
||||||
}
|
|
||||||
@:}
|
|
||||||
@:
|
|
||||||
@:<h2>@@Model.ViewName</h2>
|
|
||||||
@:
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
@:@@{
|
|
||||||
@:Layout = "null";
|
|
||||||
@:}
|
|
||||||
@:
|
|
||||||
@:<!DOCTYPE html>
|
|
||||||
@:
|
|
||||||
@:<html>
|
|
||||||
@:<head>
|
|
||||||
@:<meta name="viewport" content="width=device-width" />
|
|
||||||
@:<title>@@@Model.ViewName</title>
|
|
||||||
@:</head>
|
|
||||||
@:<body>
|
|
||||||
@:
|
|
||||||
// PushIndent(" ");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
<h3>@AreYourSureYouWantToDeleteThis</h3>
|
|
||||||
<div>
|
|
||||||
<h4>@@@Model.ViewDataTypeShortName</h4>
|
|
||||||
<hr />
|
|
||||||
<dl class="dl-horizontal">
|
|
||||||
@{
|
|
||||||
foreach (var property in Model.ModelMetadata.Properties)
|
|
||||||
{
|
|
||||||
if (property.Scaffold && !property.IsPrimaryKey && !property.IsForeignKey)
|
|
||||||
{
|
|
||||||
<dt>
|
|
||||||
@@Html.DisplayNameFor(model => model.@GetValueExpression(property))
|
|
||||||
</dt>
|
|
||||||
<dd>
|
|
||||||
@@Html.DisplayFor(model => model.@GetValueExpression(property))
|
|
||||||
</dd>
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@:</dl>
|
|
||||||
@:
|
|
||||||
@:<form asp-action="@Model.ViewName">
|
|
||||||
@:<div class="form-actions no-color">
|
|
||||||
@:<input type="submit" value="@Delete" class="btn btn-default" /> |
|
|
||||||
@:<a asp-action="Index">Back to List</a>
|
|
||||||
@:</div>
|
|
||||||
@:</form>
|
|
||||||
@:</div>
|
|
||||||
if (!Model.IsPartialView && !Model.IsLayoutPageSelected)
|
|
||||||
{
|
|
||||||
//ClearIndent();
|
|
||||||
@:</body>
|
|
||||||
@:</html>
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@functions
|
|
||||||
{
|
|
||||||
string GetValueExpression(PropertyMetadata property)
|
|
||||||
{
|
|
||||||
//Todo: Get the association for the property and use that.
|
|
||||||
return property.PropertyName;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,95 +0,0 @@
|
|||||||
@inherits Microsoft.Extensions.CodeGeneration.Templating.RazorTemplateBase
|
|
||||||
@using Microsoft.Extensions.CodeGeneration.EntityFramework
|
|
||||||
@@model @Model.ViewDataTypeName
|
|
||||||
|
|
||||||
@{
|
|
||||||
if (Model.IsPartialView)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
else if (Model.IsLayoutPageSelected)
|
|
||||||
{
|
|
||||||
@:@@{
|
|
||||||
@:ViewData["Title"] = @@Model.ViewName;
|
|
||||||
if (!string.IsNullOrEmpty(Model.LayoutPageFile))
|
|
||||||
{
|
|
||||||
@:Layout = "@Model.LayoutPageFile";
|
|
||||||
}
|
|
||||||
@:}
|
|
||||||
@:
|
|
||||||
@:<h2>@@Model.ViewName</h2>
|
|
||||||
@:
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
@:@@{
|
|
||||||
@:Layout = "null";
|
|
||||||
@:}
|
|
||||||
@:
|
|
||||||
@:<!DOCTYPE html>
|
|
||||||
@:
|
|
||||||
@:<html>
|
|
||||||
@:<head>
|
|
||||||
@:<meta name="viewport" content="width=device-width" />
|
|
||||||
@:<title>@Model.ViewName</title>
|
|
||||||
@:</head>
|
|
||||||
@:<body>
|
|
||||||
@:
|
|
||||||
// PushIndent(" ");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
<div>
|
|
||||||
<h4>@Model.ViewDataTypeShortName</h4>
|
|
||||||
<hr />
|
|
||||||
<dl class="dl-horizontal">
|
|
||||||
@{
|
|
||||||
foreach (var property in Model.ModelMetadata.Properties)
|
|
||||||
{
|
|
||||||
if (property.Scaffold && !property.IsPrimaryKey && !property.IsForeignKey)
|
|
||||||
{
|
|
||||||
<dt>
|
|
||||||
@@Html.DisplayNameFor(model => model.@GetValueExpression(property))
|
|
||||||
</dt>
|
|
||||||
<dd>
|
|
||||||
@@Html.DisplayFor(model => model.@GetValueExpression(property))
|
|
||||||
</dd>
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} </dl>
|
|
||||||
</div>
|
|
||||||
<p>
|
|
||||||
@{
|
|
||||||
string pkName = GetPrimaryKeyName();
|
|
||||||
if (pkName != null)
|
|
||||||
{
|
|
||||||
@:<a asp-action="Edit" asp-route-id="@@Model.@pkName">@Edit</a> |
|
|
||||||
@:<a asp-action="Index">Back to List</a>
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
@:@@Html.ActionLink(@Edit, "Edit", new { /* id = Model.PrimaryKey */ }) |
|
|
||||||
@:<a asp-action="Index">Back to List</a>
|
|
||||||
}
|
|
||||||
}</p>
|
|
||||||
@{
|
|
||||||
if (!Model.IsPartialView && !Model.IsLayoutPageSelected)
|
|
||||||
{
|
|
||||||
//ClearIndent();
|
|
||||||
@:</body>
|
|
||||||
@:</html>
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@functions
|
|
||||||
{
|
|
||||||
string GetPrimaryKeyName()
|
|
||||||
{
|
|
||||||
return (Model.ModelMetadata.PrimaryKeys != null && Model.ModelMetadata.PrimaryKeys.Length == 1)
|
|
||||||
? Model.ModelMetadata.PrimaryKeys[0].PropertyName
|
|
||||||
: null;
|
|
||||||
}
|
|
||||||
|
|
||||||
string GetValueExpression(PropertyMetadata property)
|
|
||||||
{
|
|
||||||
//Todo: Get the association for the property and use that.
|
|
||||||
return property.PropertyName;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,149 +0,0 @@
|
|||||||
@inherits Microsoft.Extensions.CodeGeneration.Templating.RazorTemplateBase
|
|
||||||
@using Microsoft.Extensions.CodeGeneration.EntityFramework
|
|
||||||
@@model @Model.ViewDataTypeName
|
|
||||||
|
|
||||||
@{
|
|
||||||
if (Model.IsPartialView)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
else if (Model.IsLayoutPageSelected)
|
|
||||||
{
|
|
||||||
@:@@{
|
|
||||||
@:ViewData["Title"] = @@Model.ViewName;
|
|
||||||
if (!string.IsNullOrEmpty(Model.LayoutPageFile))
|
|
||||||
{
|
|
||||||
@:Layout = "@Model.LayoutPageFile";
|
|
||||||
}
|
|
||||||
@:}
|
|
||||||
@:
|
|
||||||
@:<h2>@@Model.ViewName</h2>
|
|
||||||
@:
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
@:@@{
|
|
||||||
@:Layout = "null";
|
|
||||||
@:}
|
|
||||||
@:
|
|
||||||
@:<!DOCTYPE html>
|
|
||||||
@:
|
|
||||||
@:<html>
|
|
||||||
@:<head>
|
|
||||||
@:<meta name="viewport" content="width=device-width" />
|
|
||||||
@:<title>@@Model.ViewName</title>
|
|
||||||
@:</head>
|
|
||||||
@:<body>
|
|
||||||
@:
|
|
||||||
// PushIndent(" ");
|
|
||||||
}
|
|
||||||
@:<form asp-action="@Model.ViewName">
|
|
||||||
@:<div class="form-horizontal">
|
|
||||||
@:<h4>@Model.ViewDataTypeShortName</h4>
|
|
||||||
@:<hr />
|
|
||||||
@:<div asp-validation-summary="ModelOnly" class="text-danger"></div>
|
|
||||||
foreach (PropertyMetadata property in Model.ModelMetadata.Properties)
|
|
||||||
{
|
|
||||||
if (property.Scaffold)
|
|
||||||
{
|
|
||||||
if (property.IsPrimaryKey)
|
|
||||||
{
|
|
||||||
@:<input type="hidden" asp-for="@property.PropertyName" />
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (property.IsReadOnly)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (property.IsForeignKey)
|
|
||||||
{
|
|
||||||
@:<div class="form-group">
|
|
||||||
@:<label asp-for="@property.PropertyName" class="control-label col-md-2">@GetAssociationName(property)</label>
|
|
||||||
@:<div class="col-md-10">
|
|
||||||
@:<select asp-for="@property.PropertyName" class="form-control" ></select>
|
|
||||||
@:<span asp-validation-for="@property.PropertyName" class="text-danger" ></span>
|
|
||||||
@:</div>
|
|
||||||
@:</div>
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool isCheckbox = property.TypeName.Equals("System.Boolean");
|
|
||||||
if (isCheckbox)
|
|
||||||
{
|
|
||||||
@:<div class="form-group">
|
|
||||||
@:<div class="col-md-offset-2 col-md-10">
|
|
||||||
@:<div class="checkbox">
|
|
||||||
@:<input asp-for="@property.PropertyName" />
|
|
||||||
@:<label asp-for="@property.PropertyName"></label>
|
|
||||||
@:</div>
|
|
||||||
@:</div>
|
|
||||||
@:</div>
|
|
||||||
}
|
|
||||||
else if (property.IsEnum && !property.IsEnumFlags)
|
|
||||||
{
|
|
||||||
@:<div class="form-group">
|
|
||||||
@:<label asp-for="@property.PropertyName" class="col-md-2 control-label"></label>
|
|
||||||
@:<div class="col-md-10">
|
|
||||||
@:<select asp-for="@property.PropertyName" class="form-control"></select>
|
|
||||||
@:<span asp-validation-for="@property.PropertyName" class="text-danger" ></span>
|
|
||||||
@:</div>
|
|
||||||
@:</div>
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
@:<div class="form-group">
|
|
||||||
@:<label asp-for="@property.PropertyName" class="col-md-2 control-label"></label>
|
|
||||||
@:<div class="col-md-10">
|
|
||||||
@:<input asp-for="@property.PropertyName" class="form-control" />
|
|
||||||
@:<span asp-validation-for="@property.PropertyName" class="text-danger"></span>
|
|
||||||
@:</div>
|
|
||||||
@:</div>
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
<div class="form-group">
|
|
||||||
<div class="col-md-offset-2 col-md-10">
|
|
||||||
<input type="submit" value="Save" class="btn btn-default" />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
|
|
||||||
<div>
|
|
||||||
<a asp-action="Index">Back to List</a>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
@{
|
|
||||||
if (Model.ReferenceScriptLibraries && (Model.IsLayoutPageSelected || Model.IsPartialView))
|
|
||||||
{
|
|
||||||
@:@@section Scripts {
|
|
||||||
@:<script src="~/lib/jquery/dist/jquery.min.js"></script>
|
|
||||||
@:<script src="~/lib/jquery-validation/dist/jquery.validate.min.js"></script>
|
|
||||||
@:<script src="~/lib/jquery-validation-unobtrusive/jquery.validate.unobtrusive.min.js"></script>
|
|
||||||
@:}
|
|
||||||
}
|
|
||||||
// The following code closes the tag used in the case of a view using a layout page and the body and html tags in the case of a regular view page
|
|
||||||
if (!Model.IsPartialView && !Model.IsLayoutPageSelected)
|
|
||||||
{
|
|
||||||
if (Model.ReferenceScriptLibraries)
|
|
||||||
{
|
|
||||||
@:@@section Scripts {
|
|
||||||
@:<script src="~/lib/jquery/dist/jquery.min.js"></script>
|
|
||||||
@:<script src="~/lib/jquery-validation/dist/jquery.validate.min.js"></script>
|
|
||||||
@:<script src="~/lib/jquery-validation-unobtrusive/jquery.validate.unobtrusive.min.js"></script>
|
|
||||||
@:}
|
|
||||||
//ClearIndent();
|
|
||||||
}
|
|
||||||
@:</body>
|
|
||||||
@:</html>
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@functions
|
|
||||||
{
|
|
||||||
string GetAssociationName(PropertyMetadata property)
|
|
||||||
{
|
|
||||||
//Todo: Implement properly.
|
|
||||||
return property.PropertyName;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,115 +0,0 @@
|
|||||||
@inherits Microsoft.Extensions.CodeGeneration.Templating.RazorTemplateBase
|
|
||||||
@using Microsoft.Extensions.CodeGeneration.EntityFramework
|
|
||||||
@@model @GetEnumerableTypeExpression(Model.ViewDataTypeName)
|
|
||||||
|
|
||||||
@{
|
|
||||||
if (Model.IsPartialView)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
else if (Model.IsLayoutPageSelected)
|
|
||||||
{
|
|
||||||
@:@@{
|
|
||||||
@:ViewData["Title"] = @@Model.ViewName;
|
|
||||||
if (!string.IsNullOrEmpty(Model.LayoutPageFile))
|
|
||||||
{
|
|
||||||
@:Layout = "@Model.LayoutPageFile";
|
|
||||||
}
|
|
||||||
@:}
|
|
||||||
@:
|
|
||||||
@:<h2>@@Model.ViewName</h2>
|
|
||||||
@:
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
@:@@{
|
|
||||||
@:Layout = "null";
|
|
||||||
@:}
|
|
||||||
@:
|
|
||||||
@:<!DOCTYPE html>
|
|
||||||
@:
|
|
||||||
@:<html>
|
|
||||||
@:<head>
|
|
||||||
@:<meta name="viewport" content="width=device-width" />
|
|
||||||
@:<title>@@Model.ViewName</title>
|
|
||||||
@:</head>
|
|
||||||
@:<body>
|
|
||||||
// PushIndent(" ");
|
|
||||||
}
|
|
||||||
@:<p>
|
|
||||||
@:<a asp-action="Create">Create New</a>
|
|
||||||
@:</p>
|
|
||||||
@:<table class="table">
|
|
||||||
@:<tr>
|
|
||||||
IEnumerable<PropertyMetadata> properties = Model.ModelMetadata.Properties;
|
|
||||||
foreach (var property in properties)
|
|
||||||
{
|
|
||||||
if (property.Scaffold && !property.IsPrimaryKey && !property.IsForeignKey)
|
|
||||||
{
|
|
||||||
<th>
|
|
||||||
@@Html.DisplayNameFor(model => model.@GetValueExpression(property))
|
|
||||||
</th>
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@:<th></th>
|
|
||||||
@:</tr>
|
|
||||||
@:
|
|
||||||
@:@@foreach (var item in Model) {
|
|
||||||
@:<tr>
|
|
||||||
foreach (PropertyMetadata property in properties)
|
|
||||||
{
|
|
||||||
if (property.Scaffold && !property.IsPrimaryKey && !property.IsForeignKey)
|
|
||||||
{
|
|
||||||
<td>
|
|
||||||
@@Html.DisplayFor(modelItem => item.@GetValueExpression(property))
|
|
||||||
</td>
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
string pkName = GetPrimaryKeyName();
|
|
||||||
if (pkName != null)
|
|
||||||
{
|
|
||||||
@:<td>
|
|
||||||
@:<a asp-action="Edit" asp-route-id="@@item.@pkName">@Edit</a> |
|
|
||||||
@:<a asp-action="Details" asp-route-id="@@item.@pkName">@Details</a> |
|
|
||||||
@:<a asp-action="Delete" asp-route-id="@@item.@pkName">@Delete</a>
|
|
||||||
@:</td>
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
<td>
|
|
||||||
@@Html.ActionLink("Edit", "Edit",new { /* id=item.PrimaryKey */ }) |
|
|
||||||
@@Html.ActionLink("Details", "Details", new { /* id=item.PrimaryKey */ }) |
|
|
||||||
@@Html.ActionLink("Delete", "Delete", new { /* id=item.PrimaryKey */ })
|
|
||||||
</td>
|
|
||||||
}
|
|
||||||
@:</tr>
|
|
||||||
@:}
|
|
||||||
|
|
||||||
@:</table>
|
|
||||||
if(!Model.IsPartialView && !Model.IsLayoutPageSelected)
|
|
||||||
{
|
|
||||||
//ClearIndent();
|
|
||||||
@:</body>
|
|
||||||
@:</html>
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@functions
|
|
||||||
{
|
|
||||||
string GetPrimaryKeyName()
|
|
||||||
{
|
|
||||||
return (Model.ModelMetadata.PrimaryKeys != null && Model.ModelMetadata.PrimaryKeys.Length == 1)
|
|
||||||
? Model.ModelMetadata.PrimaryKeys[0].PropertyName
|
|
||||||
: null;
|
|
||||||
}
|
|
||||||
|
|
||||||
string GetValueExpression(PropertyMetadata property)
|
|
||||||
{
|
|
||||||
//Todo: Get the association for the property and use that.
|
|
||||||
return property.PropertyName;
|
|
||||||
}
|
|
||||||
|
|
||||||
string GetEnumerableTypeExpression(string typeName)
|
|
||||||
{
|
|
||||||
return "IEnumerable<" + typeName + ">";
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,78 +0,0 @@
|
|||||||
include versioning.mk
|
|
||||||
|
|
||||||
|
|
||||||
REPO_ROOT=../../../src
|
|
||||||
|
|
||||||
SUBDIRS=Yavsc Yavsc.Server Yavsc.Abstract OAuth.AspNet.AuthServer OAuth.AspNet.Token cli test
|
|
||||||
|
|
||||||
all: $(SUBDIRS)
|
|
||||||
|
|
||||||
Yavsc.Abstract:
|
|
||||||
$(MAKE) -C $(REPO_ROOT)/Yavsc.Abstract VERSION=$(VERSION)
|
|
||||||
|
|
||||||
OAuth.AspNet.Token:
|
|
||||||
$(MAKE) -C $(REPO_ROOT)/OAuth.AspNet.Token VERSION=$(VERSION)
|
|
||||||
|
|
||||||
OAuth.AspNet.AuthServer: OAuth.AspNet.Token
|
|
||||||
$(MAKE) -C $(REPO_ROOT)/OAuth.AspNet.AuthServer VERSION=$(VERSION)
|
|
||||||
|
|
||||||
Yavsc.Server: Yavsc.Abstract
|
|
||||||
$(MAKE) -C $(REPO_ROOT)/Yavsc.Server VERSION=$(VERSION)
|
|
||||||
|
|
||||||
Yavsc: Yavsc.Server OAuth.AspNet.AuthServer OAuth.AspNet.Token
|
|
||||||
make -C $(REPO_ROOT)/Yavsc VERSION=$(VERSION)
|
|
||||||
|
|
||||||
Yavsc-deploy-pkg: Yavsc
|
|
||||||
make -C $(REPO_ROOT)/Yavsc deploy-pkg
|
|
||||||
|
|
||||||
Yavsc.Server-deploy-pkg: Yavsc.Server
|
|
||||||
make -C $(REPO_ROOT)/Yavsc.Server deploy-pkg
|
|
||||||
|
|
||||||
Yavsc.Abstract-deploy-pkg: Yavsc.Abstract
|
|
||||||
make -C $(REPO_ROOT)/Yavsc.Abstract deploy-pkg
|
|
||||||
|
|
||||||
cli-deploy-pkg: cli check
|
|
||||||
make -C $(REPO_ROOT)/cli deploy-pkg
|
|
||||||
|
|
||||||
cli: Yavsc-deploy-pkg Yavsc.Server-deploy-pkg Yavsc.Abstract-deploy-pkg
|
|
||||||
make -C $(REPO_ROOT)/cli
|
|
||||||
|
|
||||||
undoLocalYavscNugetDeploy:
|
|
||||||
rm -rf ../../../packages/Yavsc.Abstract
|
|
||||||
rm -rf ../../../packages/Yavsc.Server
|
|
||||||
rm -rf ../../../packages/Yavsc
|
|
||||||
rm -rf ~/.dnx/packages/Yavsc.Abstract
|
|
||||||
rm -rf ~/.dnx/packages/Yavsc.Server
|
|
||||||
rm -rf ~/.dnx/packages/Yavsc
|
|
||||||
|
|
||||||
check: cli
|
|
||||||
make -C $(REPO_ROOT)/cli check
|
|
||||||
make -C $(REPO_ROOT)/test
|
|
||||||
|
|
||||||
test:
|
|
||||||
make -C $(REPO_ROOT)/test
|
|
||||||
|
|
||||||
pushInPre:
|
|
||||||
make -C $(REPO_ROOT)/Yavsc pushInPre
|
|
||||||
|
|
||||||
pushInProd:
|
|
||||||
make -C $(REPO_ROOT)/Yavsc pushInProd
|
|
||||||
|
|
||||||
deploy-pkgs: Yavsc-deploy-pkg Yavsc.Server-deploy-pkg Yavsc.Abstract-deploy-pkg cli-deploy-pkg
|
|
||||||
|
|
||||||
memo:
|
|
||||||
vim ~/TODO.md
|
|
||||||
|
|
||||||
rc-num:
|
|
||||||
@echo echo 1-alpha1 < $< ^ $^ @ $@
|
|
||||||
|
|
||||||
clean:
|
|
||||||
for subdir in $(SUBDIRS) ; do \
|
|
||||||
make -C $(REPO_ROOT)/$${subdir} clean ; \
|
|
||||||
done
|
|
||||||
|
|
||||||
watch:
|
|
||||||
make -C $(REPO_ROOT)/Yavsc watch
|
|
||||||
|
|
||||||
.PHONY: all $(SUBDIRS)
|
|
||||||
|
|
@ -1,71 +0,0 @@
|
|||||||
# Common defs
|
|
||||||
#
|
|
||||||
|
|
||||||
ifndef PRJNAME
|
|
||||||
PRJNAME := $(shell basename `pwd -P`)
|
|
||||||
endif
|
|
||||||
FRAMEWORK=dnx451
|
|
||||||
ASPNET_ENV=Development
|
|
||||||
ASPNET_LOG_LEVEL=Debug
|
|
||||||
HOSTING=localhost
|
|
||||||
HOSTADMIN=root
|
|
||||||
FRAMEWORKALIAS=dnx451
|
|
||||||
# nuget package destination, at generation time
|
|
||||||
BINTARGET=$(PRJNAME).dll
|
|
||||||
BINTARGETPATH=bin/$(CONFIGURATION)/$(FRAMEWORKALIAS)/$(BINTARGET)
|
|
||||||
PKGFILENAME=$(PRJNAME).$(VERSION).nupkg
|
|
||||||
dnu=dnu
|
|
||||||
|
|
||||||
# OBS SUBDIRS=Yavsc.Server Yavsc.Abstract Yavsc cli
|
|
||||||
#
|
|
||||||
|
|
||||||
# Git commit hash, in order to not publish some uncrontrolled code in production environment
|
|
||||||
#
|
|
||||||
|
|
||||||
git_status := $(shell git status -s --porcelain |wc -l)
|
|
||||||
|
|
||||||
all: $(BINTARGETPATH)
|
|
||||||
|
|
||||||
fixSystemXML:
|
|
||||||
@# fixing package id reference case, to System.Xml, from package NJsonSchema.CodeGeneration.CSharp
|
|
||||||
@sed 's/System.XML/System.Xml/' project.lock.json > project.lock.json.new && mv project.lock.json.new project.lock.json
|
|
||||||
|
|
||||||
restore:
|
|
||||||
touch project.json
|
|
||||||
$(dnu) restore --ignore-failed-sources
|
|
||||||
|
|
||||||
project.lock.json: project.json
|
|
||||||
$(dnu) restore --ignore-failed-sources
|
|
||||||
|
|
||||||
watch: project.lock.json
|
|
||||||
MONO_OPTIONS=--debug MONO_MANAGED_WATCHER=enabled ASPNET_ENV=$(ASPNET_ENV) ASPNET_LOG_LEVEL=$(ASPNET_LOG_LEVEL) dnx-watch web --configuration=$(CONFIGURATION)
|
|
||||||
|
|
||||||
clean:
|
|
||||||
rm -rf bin obj
|
|
||||||
rm project.lock.json
|
|
||||||
|
|
||||||
cleanoutput:
|
|
||||||
rm -rf bin/$(CONFIGURATION)
|
|
||||||
rm -rf bin/output
|
|
||||||
|
|
||||||
$(BINTARGETPATH): project.lock.json rc-num.txt-check
|
|
||||||
$(dnu) build --configuration=$(CONFIGURATION)
|
|
||||||
|
|
||||||
# Default target, from one level sub dirs
|
|
||||||
|
|
||||||
bin/output:
|
|
||||||
$(dnu) publish
|
|
||||||
|
|
||||||
bin/output/wwwroot/version: bin/output
|
|
||||||
@echo $(version) > bin/output/wwwroot/version
|
|
||||||
|
|
||||||
pack: $(BINTARGETPATH) ../../version.txt
|
|
||||||
dnu pack --configuration $(CONFIGURATION)
|
|
||||||
|
|
||||||
push: pack
|
|
||||||
@echo push to source: $(ISNSOURCE)
|
|
||||||
isn push -s $(ISNSOURCE) -k $(NUGETSOURCEAPIKEY) src/$(PRJNAME)/bin/$(CONFIGURATION)/$(PRJNAME).*.nupkg
|
|
||||||
|
|
||||||
.PHONY: rc-num.txt-check
|
|
||||||
|
|
||||||
# .DEFAULT_GOAL := $(BINTARGETPATH)
|
|
@ -1,16 +0,0 @@
|
|||||||
|
|
||||||
|
|
||||||
MSBUILD=msbuild
|
|
||||||
MONO=mono
|
|
||||||
CONFIGURATION=Debug
|
|
||||||
BINTYPE=exe
|
|
||||||
PRJNAME := $(shell basename `pwd -P`)
|
|
||||||
|
|
||||||
rc_num := $(shell cat ../../rc-num.txt)
|
|
||||||
VERSION=1.0.5-rc$(rc_num)
|
|
||||||
|
|
||||||
BINTARGET=$(PRJNAME).$(BINTYPE)
|
|
||||||
BINTARGETPATH=bin/$(CONFIGURATION)/$(BINTARGET)
|
|
||||||
ISNSOURCE=$(HOME)/Nupkgs
|
|
||||||
PKGFILENAME=$(PRJNAME).$(VERSION).nupkg
|
|
||||||
|
|
@ -1,16 +0,0 @@
|
|||||||
|
|
||||||
ifndef PRJNAME
|
|
||||||
PRJNAME := $(shell basename `pwd -P`)
|
|
||||||
endif
|
|
||||||
version := $(shell cat ../../version.txt)
|
|
||||||
MAKE=make
|
|
||||||
ISNSOURCE=$(HOME)/Nupkgs
|
|
||||||
VERSION=$(version)
|
|
||||||
CONFIGURATION=Debug
|
|
||||||
|
|
||||||
version-check:
|
|
||||||
ifndef version
|
|
||||||
@echo no version number specification ... please, could you try and run 'echo 1.2.3 > ../../version.txt' ?.
|
|
||||||
else
|
|
||||||
@echo 'Got version number : $(version)'
|
|
||||||
endif
|
|
@ -1,44 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
|
|
||||||
version="$1"
|
|
||||||
major=0
|
|
||||||
minor=0
|
|
||||||
build=0
|
|
||||||
|
|
||||||
# break down the version number into it's components
|
|
||||||
regex="([0-9]+).([0-9]+).([0-9]+)((-[A-Za-z]+)([0-9]+))?"
|
|
||||||
if [[ $version =~ $regex ]]; then
|
|
||||||
major="${BASH_REMATCH[1]}"
|
|
||||||
minor="${BASH_REMATCH[2]}"
|
|
||||||
build="${BASH_REMATCH[3]}"
|
|
||||||
patchtype="${BASH_REMATCH[5]}"
|
|
||||||
patchnum="${BASH_REMATCH[6]}"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# check paramater to see which number to increment
|
|
||||||
if [[ "$2" == "feature" ]]; then
|
|
||||||
minor=$(echo $minor + 1 | bc)
|
|
||||||
build=0
|
|
||||||
patchtype=
|
|
||||||
patchnum=
|
|
||||||
elif [[ "$2" == "build" ]]; then
|
|
||||||
build=$(echo $build + 1 | bc)
|
|
||||||
patchtype=
|
|
||||||
patchnum=
|
|
||||||
elif [[ "$2" == "major" ]]; then
|
|
||||||
major=$(echo $major+1 | bc)
|
|
||||||
minor=0
|
|
||||||
build=0
|
|
||||||
patchtype=
|
|
||||||
patchnum=
|
|
||||||
elif [[ "$2" == "patch" ]]; then
|
|
||||||
patchnum=$(echo $patchnum + 1 | bc)
|
|
||||||
else
|
|
||||||
echo "usage: ./version.sh version_number [major/feature/build/patch]" >&2
|
|
||||||
|
|
||||||
exit -1
|
|
||||||
fi
|
|
||||||
|
|
||||||
# echo the new version number
|
|
||||||
echo "${major}.${minor}.${build}${patchtype}${patchnum}"
|
|
||||||
|
|
10
src/Api/Api.csproj
Normal file
10
src/Api/Api.csproj
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
|
</PropertyGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="8.0.12" />
|
||||||
|
</ItemGroup>
|
||||||
|
</Project>
|
77
src/Api/Program.cs
Normal file
77
src/Api/Program.cs
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
/*
|
||||||
|
Copyright (c) 2024 HigginsSoft, Alexander Higgins - https://github.com/alexhiggins732/
|
||||||
|
|
||||||
|
Copyright (c) 2018, Brock Allen & Dominick Baier. All rights reserved.
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information.
|
||||||
|
Source code and license this software can be found
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
*/
|
||||||
|
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
|
||||||
|
internal class Program
|
||||||
|
{
|
||||||
|
private static async Task Main(string[] args)
|
||||||
|
{
|
||||||
|
Console.Title = "API";
|
||||||
|
|
||||||
|
var builder = WebApplication.CreateBuilder(args);
|
||||||
|
|
||||||
|
var services = builder.Services;
|
||||||
|
|
||||||
|
// accepts any access token issued by identity server
|
||||||
|
// adds an authorization policy for scope 'api1'
|
||||||
|
services
|
||||||
|
.AddAuthorization(options =>
|
||||||
|
{
|
||||||
|
options.AddPolicy("ApiScope", policy =>
|
||||||
|
{
|
||||||
|
policy
|
||||||
|
.RequireAuthenticatedUser()
|
||||||
|
.RequireClaim("scope", "scope2");
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.AddCors(options =>
|
||||||
|
{
|
||||||
|
// this defines a CORS policy called "default"
|
||||||
|
options.AddPolicy("default", policy =>
|
||||||
|
{
|
||||||
|
policy.WithOrigins("https://localhost:5003")
|
||||||
|
.AllowAnyHeader()
|
||||||
|
.AllowAnyMethod();
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.AddControllers();
|
||||||
|
|
||||||
|
// accepts any access token issued by identity server
|
||||||
|
var authenticationBuilder = services.AddAuthentication()
|
||||||
|
.AddJwtBearer("Bearer", options =>
|
||||||
|
{
|
||||||
|
options.IncludeErrorDetails = true;
|
||||||
|
options.Authority = "https://localhost:5001";
|
||||||
|
options.TokenValidationParameters =
|
||||||
|
new() { ValidateAudience = false };
|
||||||
|
});
|
||||||
|
|
||||||
|
using (var app = builder.Build())
|
||||||
|
{
|
||||||
|
if (app.Environment.IsDevelopment())
|
||||||
|
app.UseDeveloperExceptionPage();
|
||||||
|
|
||||||
|
app
|
||||||
|
.UseRouting()
|
||||||
|
.UseAuthentication()
|
||||||
|
.UseAuthorization()
|
||||||
|
.UseCors("default");
|
||||||
|
|
||||||
|
app.MapGet("/identity", (HttpContext context) =>
|
||||||
|
new JsonResult(context?.User?.Claims.Select(c => new { c.Type, c.Value }))
|
||||||
|
).RequireAuthorization("ApiScope");
|
||||||
|
|
||||||
|
await app.RunAsync();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
10
src/Api/appsettings.json
Normal file
10
src/Api/appsettings.json
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
{
|
||||||
|
"Logging": {
|
||||||
|
"LogLevel": {
|
||||||
|
"Default": "Information",
|
||||||
|
"Microsoft": "Warning",
|
||||||
|
"Microsoft.Hosting.Lifetime": "Information"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"AllowedHosts": "*"
|
||||||
|
}
|
@ -77,10 +77,12 @@ public static class Config
|
|||||||
PostLogoutRedirectUris = { "https://localhost:5003/signout-callback-oidc" },
|
PostLogoutRedirectUris = { "https://localhost:5003/signout-callback-oidc" },
|
||||||
|
|
||||||
AllowOfflineAccess = true,
|
AllowOfflineAccess = true,
|
||||||
|
|
||||||
AllowedScopes = {
|
AllowedScopes = {
|
||||||
IdentityServerConstants.StandardScopes.OpenId,
|
IdentityServerConstants.StandardScopes.OpenId,
|
||||||
IdentityServerConstants.StandardScopes.Profile,
|
IdentityServerConstants.StandardScopes.Profile,
|
||||||
IdentityServerConstants.StandardScopes.Email,
|
IdentityServerConstants.StandardScopes.Email,
|
||||||
|
IdentityServerConstants.StandardScopes.OfflineAccess,
|
||||||
"scope2" }
|
"scope2" }
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
@ -2,6 +2,7 @@ using System.Globalization;
|
|||||||
using System.Security.Cryptography.X509Certificates;
|
using System.Security.Cryptography.X509Certificates;
|
||||||
using Google.Apis.Util.Store;
|
using Google.Apis.Util.Store;
|
||||||
using IdentityServer8;
|
using IdentityServer8;
|
||||||
|
using IdentityServer8.Hosting;
|
||||||
using IdentityServer8.Services;
|
using IdentityServer8.Services;
|
||||||
using Microsoft.AspNetCore.Authentication;
|
using Microsoft.AspNetCore.Authentication;
|
||||||
using Microsoft.AspNetCore.Authorization;
|
using Microsoft.AspNetCore.Authorization;
|
||||||
@ -187,8 +188,9 @@ internal static class HostingExtensions
|
|||||||
.AddInMemoryClients(Config.Clients)
|
.AddInMemoryClients(Config.Clients)
|
||||||
.AddInMemoryApiScopes(Config.ApiScopes)
|
.AddInMemoryApiScopes(Config.ApiScopes)
|
||||||
.AddAspNetIdentity<ApplicationUser>()
|
.AddAspNetIdentity<ApplicationUser>()
|
||||||
|
.AddJwtBearerClientAuthentication()
|
||||||
;
|
;
|
||||||
services.AddScoped<IProfileService, ProfileService>();
|
//services.AddScoped<IProfileService, ProfileService>();
|
||||||
|
|
||||||
if (builder.Environment.IsDevelopment())
|
if (builder.Environment.IsDevelopment())
|
||||||
{
|
{
|
||||||
@ -207,7 +209,15 @@ internal static class HostingExtensions
|
|||||||
// TODO .AddServerSideSessionStore<YavscServerSideSessionStore>()
|
// TODO .AddServerSideSessionStore<YavscServerSideSessionStore>()
|
||||||
|
|
||||||
|
|
||||||
var authenticationBuilder = services.AddAuthentication();
|
|
||||||
|
var authenticationBuilder = services.AddAuthentication()
|
||||||
|
.AddJwtBearer("Bearer", options =>
|
||||||
|
{
|
||||||
|
options.IncludeErrorDetails=true;
|
||||||
|
options.Authority = "https://localhost:5001";
|
||||||
|
options.TokenValidationParameters =
|
||||||
|
new() { ValidateAudience = false };
|
||||||
|
});
|
||||||
|
|
||||||
authenticationBuilder.AddGoogle(options =>
|
authenticationBuilder.AddGoogle(options =>
|
||||||
{
|
{
|
||||||
@ -251,13 +261,7 @@ internal static class HostingExtensions
|
|||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
services.AddCors(options =>
|
|
||||||
{
|
|
||||||
options.AddPolicy("CorsPolicy", builder =>
|
|
||||||
{
|
|
||||||
_ = builder.WithOrigins("*");
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
// Add the system clock service
|
// Add the system clock service
|
||||||
@ -313,10 +317,10 @@ internal static class HostingExtensions
|
|||||||
services.AddAuthorization(options =>
|
services.AddAuthorization(options =>
|
||||||
{
|
{
|
||||||
options.AddPolicy("ApiScope", policy =>
|
options.AddPolicy("ApiScope", policy =>
|
||||||
{
|
{
|
||||||
policy.RequireAuthenticatedUser()
|
policy.RequireAuthenticatedUser()
|
||||||
.RequireClaim("scope", "scope2");
|
.RequireClaim("scope", "scope2");
|
||||||
});
|
});
|
||||||
options.AddPolicy("Performer", policy =>
|
options.AddPolicy("Performer", policy =>
|
||||||
{
|
{
|
||||||
policy
|
policy
|
||||||
@ -334,11 +338,29 @@ internal static class HostingExtensions
|
|||||||
// options.AddPolicy("BuildingEntry", policy => policy.Requirements.Add(new OfficeEntryRequirement()));
|
// options.AddPolicy("BuildingEntry", policy => policy.Requirements.Add(new OfficeEntryRequirement()));
|
||||||
options.AddPolicy("Authenticated", policy => policy.RequireAuthenticatedUser());
|
options.AddPolicy("Authenticated", policy => policy.RequireAuthenticatedUser());
|
||||||
options.AddPolicy("IsTheAuthor", policy => policy.Requirements.Add(new EditPermission()));
|
options.AddPolicy("IsTheAuthor", policy => policy.Requirements.Add(new EditPermission()));
|
||||||
|
})
|
||||||
|
.AddCors(options =>
|
||||||
|
{
|
||||||
|
options.AddPolicy("CorsPolicy", builder =>
|
||||||
|
{
|
||||||
|
_ = builder.WithOrigins("*")
|
||||||
|
.AllowAnyHeader()
|
||||||
|
.AllowAnyMethod();
|
||||||
|
});
|
||||||
|
|
||||||
|
options.AddPolicy("default", policy =>
|
||||||
|
{
|
||||||
|
policy.WithOrigins("https://localhost:5003")
|
||||||
|
.AllowAnyHeader()
|
||||||
|
.AllowAnyMethod();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
services.AddSingleton<IAuthorizationHandler, PermissionHandler>();
|
services.AddSingleton<IAuthorizationHandler, PermissionHandler>();
|
||||||
|
|
||||||
|
|
||||||
|
// accepts any access token issued by identity server
|
||||||
|
|
||||||
return builder.Build();
|
return builder.Build();
|
||||||
}
|
}
|
||||||
public static WebApplication ConfigurePipeline(this WebApplication app)
|
public static WebApplication ConfigurePipeline(this WebApplication app)
|
||||||
@ -357,9 +379,6 @@ internal static class HostingExtensions
|
|||||||
app.UseRouting();
|
app.UseRouting();
|
||||||
app.UseIdentityServer();
|
app.UseIdentityServer();
|
||||||
app.UseAuthorization();
|
app.UseAuthorization();
|
||||||
app.MapGet("/api/me", (HttpContext context) =>
|
|
||||||
new JsonResult(context?.User?.Claims.Select(c => new { c.Type, c.Value }))
|
|
||||||
).RequireAuthorization("ApiScope");
|
|
||||||
app.MapControllerRoute(
|
app.MapControllerRoute(
|
||||||
name: "default",
|
name: "default",
|
||||||
pattern: "{controller=Home}/{action=Index}/{id?}");
|
pattern: "{controller=Home}/{action=Index}/{id?}");
|
||||||
|
@ -8,11 +8,11 @@ using Yavsc.Models;
|
|||||||
|
|
||||||
namespace Yavsc.Services
|
namespace Yavsc.Services
|
||||||
{
|
{
|
||||||
public class ProfileService : IProfileService
|
public class ProfileService : DefaultProfileService, IProfileService
|
||||||
{
|
{
|
||||||
private readonly UserManager<ApplicationUser> _userManager;
|
private readonly UserManager<ApplicationUser> _userManager;
|
||||||
public ProfileService(
|
public ProfileService(
|
||||||
UserManager<ApplicationUser> userManager)
|
UserManager<ApplicationUser> userManager, ILogger<DefaultProfileService> logger) : base(logger)
|
||||||
{
|
{
|
||||||
_userManager = userManager;
|
_userManager = userManager;
|
||||||
}
|
}
|
||||||
@ -21,50 +21,56 @@ namespace Yavsc.Services
|
|||||||
ProfileDataRequestContext context,
|
ProfileDataRequestContext context,
|
||||||
ApplicationUser user)
|
ApplicationUser user)
|
||||||
{
|
{
|
||||||
|
var requestedApiResources = context.RequestedResources.Resources.ApiResources.Select(
|
||||||
|
r => r.Name
|
||||||
|
).ToArray();
|
||||||
|
var requestedApiScopes = context.RequestedResources.Resources.ApiScopes.Select(
|
||||||
|
s => s.Name
|
||||||
|
).ToArray();
|
||||||
|
|
||||||
var allowedScopes = context.Client.AllowedScopes
|
var requestedScopes = context.Client.AllowedScopes
|
||||||
.Where(s => s != JwtClaimTypes.Subject)
|
.Where(s => s != JwtClaimTypes.Subject
|
||||||
|
&& requestedApiScopes.Contains(s))
|
||||||
.ToList();
|
.ToList();
|
||||||
if (allowedScopes.Contains("profile"))
|
|
||||||
|
if (context.RequestedClaimTypes.Contains("profile"))
|
||||||
|
if (requestedScopes.Contains("profile"))
|
||||||
{
|
{
|
||||||
allowedScopes.Remove("profile");
|
requestedScopes.Remove("profile");
|
||||||
allowedScopes.Add(JwtClaimTypes.Name);
|
requestedScopes.Add(JwtClaimTypes.Name);
|
||||||
allowedScopes.Add(JwtClaimTypes.FamilyName);
|
requestedScopes.Add(JwtClaimTypes.FamilyName);
|
||||||
allowedScopes.Add(JwtClaimTypes.Email);
|
requestedScopes.Add(JwtClaimTypes.Email);
|
||||||
allowedScopes.Add(JwtClaimTypes.PreferredUserName);
|
requestedScopes.Add(JwtClaimTypes.PreferredUserName);
|
||||||
allowedScopes.Add("http://schemas.microsoft.com/ws/2008/06/identity/claims/role");
|
requestedScopes.Add(JwtClaimTypes.Role);
|
||||||
}
|
}
|
||||||
|
|
||||||
var claims = new List<Claim> {
|
var claims = new List<Claim> {
|
||||||
new Claim(JwtClaimTypes.Subject,user.Id.ToString()),
|
new Claim(JwtClaimTypes.Subject,user.Id.ToString()),
|
||||||
};
|
};
|
||||||
|
if (requestedScopes.Contains(JwtClaimTypes.Name)||
|
||||||
foreach (var subClaim in context.Subject.Claims)
|
requestedScopes.Contains(JwtClaimTypes.FamilyName))
|
||||||
{
|
{
|
||||||
if (allowedScopes.Contains(subClaim.Type))
|
claims.Add(new Claim(JwtClaimTypes.Name, user.FullName));
|
||||||
claims.Add(subClaim);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
AddClaims(allowedScopes, claims, JwtClaimTypes.Email, user.Email);
|
if (requestedScopes.Contains(JwtClaimTypes.PreferredUserName) )
|
||||||
AddClaims(allowedScopes, claims, JwtClaimTypes.PreferredUserName, user.FullName);
|
|
||||||
|
|
||||||
foreach (var scope in context.Client.AllowedScopes)
|
|
||||||
{
|
{
|
||||||
claims.Add(new Claim("scope", scope));
|
claims.Add(new Claim(JwtClaimTypes.Name, user.UserName));
|
||||||
|
}
|
||||||
|
if (requestedScopes.Contains(JwtClaimTypes.Email))
|
||||||
|
claims.Add(new Claim(JwtClaimTypes.Email, user.Email));
|
||||||
|
|
||||||
|
if (requestedScopes.Contains(JwtClaimTypes.Role))
|
||||||
|
{
|
||||||
|
var roles = await this._userManager.GetRolesAsync(user);
|
||||||
|
if (roles.Count()>0)
|
||||||
|
{
|
||||||
|
claims.Add(new Claim(JwtClaimTypes.Role,String.Join(" ",roles)));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return claims;
|
return claims;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void AddClaims(List<string> allowedScopes, List<Claim> claims,
|
|
||||||
string claimType, string claimValue
|
|
||||||
)
|
|
||||||
{
|
|
||||||
if (allowedScopes.Contains(claimType))
|
|
||||||
if (!claims.Any(c => c.Type == claimType))
|
|
||||||
claims.Add(new Claim(claimType, claimValue));
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task GetProfileDataAsync(ProfileDataRequestContext context)
|
public async Task GetProfileDataAsync(ProfileDataRequestContext context)
|
||||||
{
|
{
|
||||||
var subjectId = context.Subject.Claims.FirstOrDefault(c => c.Type == "sub").Value;
|
var subjectId = context.Subject.Claims.FirstOrDefault(c => c.Type == "sub").Value;
|
||||||
@ -72,7 +78,6 @@ namespace Yavsc.Services
|
|||||||
context.IssuedClaims = await GetClaimsFromUserAsync(context, user);
|
context.IssuedClaims = await GetClaimsFromUserAsync(context, user);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public async Task IsActiveAsync(IsActiveContext context)
|
public async Task IsActiveAsync(IsActiveContext context)
|
||||||
{
|
{
|
||||||
var subjectId = context.Subject.Claims.FirstOrDefault(c => c.Type == "sub").Value;
|
var subjectId = context.Subject.Claims.FirstOrDefault(c => c.Type == "sub").Value;
|
||||||
|
@ -54,14 +54,31 @@ namespace testOauthClient.Controllers
|
|||||||
public async Task<IActionResult> GetUserInfo(CancellationToken cancellationToken)
|
public async Task<IActionResult> GetUserInfo(CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
var accessToken = await HttpContext.GetTokenAsync("access_token");
|
var accessToken = await HttpContext.GetTokenAsync("access_token");
|
||||||
var client = new HttpClient();
|
var client = new HttpClient(new HttpClientHandler(){ AllowAutoRedirect=false });
|
||||||
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", accessToken);
|
|
||||||
client.DefaultRequestHeaders.Add("Accept", "application/json");
|
client.DefaultRequestHeaders.Add("Accept", "application/json");
|
||||||
var content = await client.GetStringAsync("https://localhost:5001/api/account/me");
|
client.SetBearerToken(accessToken);
|
||||||
var obj = JsonSerializer.Deserialize<JsonElement>(content);
|
var content = await client.GetAsync("https://localhost:5001/api/account/me");
|
||||||
|
content.EnsureSuccessStatusCode();
|
||||||
|
var json = await content.Content.ReadAsStreamAsync();
|
||||||
|
var obj = JsonSerializer.Deserialize<JsonElement>(json);
|
||||||
return View("UserInfo", obj.ToString());
|
return View("UserInfo", obj.ToString());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[HttpPost]
|
||||||
|
public async Task<IActionResult> GetApiCall(CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
var accessToken = await HttpContext.GetTokenAsync("access_token");
|
||||||
|
var client = new HttpClient(new HttpClientHandler(){ AllowAutoRedirect=false });
|
||||||
|
client.DefaultRequestHeaders.Add("Accept", "application/json");
|
||||||
|
client.SetBearerToken(accessToken);
|
||||||
|
var content = await client.GetAsync("https://localhost:6001/identity");
|
||||||
|
content.EnsureSuccessStatusCode();
|
||||||
|
var json = await content.Content.ReadAsStreamAsync();
|
||||||
|
var obj = JsonSerializer.Deserialize<JsonElement>(json);
|
||||||
|
return View("UserInfo", obj.ToString());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public IActionResult About()
|
public IActionResult About()
|
||||||
{
|
{
|
||||||
ViewData["Message"] = "Your application description page.";
|
ViewData["Message"] = "Your application description page.";
|
||||||
|
@ -4,8 +4,8 @@
|
|||||||
"windowsAuthentication": false,
|
"windowsAuthentication": false,
|
||||||
"anonymousAuthentication": true,
|
"anonymousAuthentication": true,
|
||||||
"iisExpress": {
|
"iisExpress": {
|
||||||
"applicationUrl": "http://localhost:16967",
|
"applicationUrl": "http://localhost:5002",
|
||||||
"sslPort": 44387
|
"sslPort": 5003
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"profiles": {
|
"profiles": {
|
||||||
@ -13,7 +13,7 @@
|
|||||||
"commandName": "Project",
|
"commandName": "Project",
|
||||||
"dotnetRunMessages": true,
|
"dotnetRunMessages": true,
|
||||||
"launchBrowser": true,
|
"launchBrowser": true,
|
||||||
"applicationUrl": "http://localhost:5164",
|
"applicationUrl": "http://localhost:5002",
|
||||||
"environmentVariables": {
|
"environmentVariables": {
|
||||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||||
}
|
}
|
||||||
@ -22,7 +22,7 @@
|
|||||||
"commandName": "Project",
|
"commandName": "Project",
|
||||||
"dotnetRunMessages": true,
|
"dotnetRunMessages": true,
|
||||||
"launchBrowser": true,
|
"launchBrowser": true,
|
||||||
"applicationUrl": "https://localhost:7055;http://localhost:5164",
|
"applicationUrl": "https://localhost:5003;http://localhost:5002",
|
||||||
"environmentVariables": {
|
"environmentVariables": {
|
||||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||||
}
|
}
|
||||||
|
@ -23,7 +23,6 @@ public class Startup
|
|||||||
.AddOpenIdConnect("Yavsc", options =>
|
.AddOpenIdConnect("Yavsc", options =>
|
||||||
{
|
{
|
||||||
options.Authority = "https://localhost:5001";
|
options.Authority = "https://localhost:5001";
|
||||||
|
|
||||||
options.ClientId = "mvc";
|
options.ClientId = "mvc";
|
||||||
options.ClientSecret = "49C1A7E1-0C79-4A89-A3D6-A37998FB86B0";
|
options.ClientSecret = "49C1A7E1-0C79-4A89-A3D6-A37998FB86B0";
|
||||||
options.ResponseType = "code";
|
options.ResponseType = "code";
|
||||||
@ -32,6 +31,8 @@ public class Startup
|
|||||||
options.Scope.Add("openid");
|
options.Scope.Add("openid");
|
||||||
options.Scope.Add("profile");
|
options.Scope.Add("profile");
|
||||||
options.Scope.Add("email");
|
options.Scope.Add("email");
|
||||||
|
options.Scope.Add("offline_access");
|
||||||
|
options.Scope.Add("scope2");
|
||||||
|
|
||||||
options.GetClaimsFromUserInfoEndpoint = true;
|
options.GetClaimsFromUserInfoEndpoint = true;
|
||||||
options.SaveTokens = true;
|
options.SaveTokens = true;
|
||||||
@ -44,6 +45,7 @@ public class Startup
|
|||||||
NameClaimType = "name",
|
NameClaimType = "name",
|
||||||
RoleClaimType = "http://schemas.microsoft.com/ws/2008/06/identity/claims/role"
|
RoleClaimType = "http://schemas.microsoft.com/ws/2008/06/identity/claims/role"
|
||||||
};
|
};
|
||||||
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -21,6 +21,11 @@
|
|||||||
<form action="~/Home/GetUserInfo" method="post">
|
<form action="~/Home/GetUserInfo" method="post">
|
||||||
<button class="btn btn-lg btn-warning" type="submit">Get user info</button>
|
<button class="btn btn-lg btn-warning" type="submit">Get user info</button>
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
|
<form action="~/Home/GetApiCall" method="post">
|
||||||
|
<button class="btn btn-lg btn-warning" type="submit">Api Call</button>
|
||||||
|
</form>
|
||||||
|
|
||||||
<form action="~/Home/PostDeviceInfo" method="post">
|
<form action="~/Home/PostDeviceInfo" method="post">
|
||||||
<button class="btn btn-lg btn-warning" type="submit">Post device info</button>
|
<button class="btn btn-lg btn-warning" type="submit">Post device info</button>
|
||||||
</form>
|
</form>
|
||||||
|
@ -1,7 +1,8 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk.Web">
|
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\Yavsc.Abstract\Yavsc.Abstract.csproj" />
|
<ProjectReference Include="..\Yavsc.Abstract\Yavsc.Abstract.csproj" />
|
||||||
<PackageReference Include="IdentityModel.AspNetCore" Version="4.3.0" />
|
<PackageReference Include="IdentityModel.AspNetCore" Version="4.3.0" />
|
||||||
|
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="8.0.12" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
@ -10,6 +11,7 @@
|
|||||||
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
|
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
|
||||||
</Content>
|
</Content>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net8.0</TargetFramework>
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
<Nullable>enable</Nullable>
|
<Nullable>enable</Nullable>
|
||||||
|
@ -15,6 +15,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Yavsc", "src\Yavsc\Yavsc.cs
|
|||||||
EndProject
|
EndProject
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "sampleWebAsWebApiClient", "src\sampleWebAsWebApiClient\sampleWebAsWebApiClient.csproj", "{38AA74FE-3932-49C3-A382-338E7C861BB1}"
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "sampleWebAsWebApiClient", "src\sampleWebAsWebApiClient\sampleWebAsWebApiClient.csproj", "{38AA74FE-3932-49C3-A382-338E7C861BB1}"
|
||||||
EndProject
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Api", "src\Api\Api.csproj", "{16CCC793-BF57-4E8B-9BB5-76283379BA3F}"
|
||||||
|
EndProject
|
||||||
Global
|
Global
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
Debug|Any CPU = Debug|Any CPU
|
Debug|Any CPU = Debug|Any CPU
|
||||||
@ -40,11 +42,16 @@ Global
|
|||||||
{38AA74FE-3932-49C3-A382-338E7C861BB1}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
{38AA74FE-3932-49C3-A382-338E7C861BB1}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
{38AA74FE-3932-49C3-A382-338E7C861BB1}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
{38AA74FE-3932-49C3-A382-338E7C861BB1}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
{38AA74FE-3932-49C3-A382-338E7C861BB1}.Release|Any CPU.Build.0 = Release|Any CPU
|
{38AA74FE-3932-49C3-A382-338E7C861BB1}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{16CCC793-BF57-4E8B-9BB5-76283379BA3F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{16CCC793-BF57-4E8B-9BB5-76283379BA3F}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{16CCC793-BF57-4E8B-9BB5-76283379BA3F}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{16CCC793-BF57-4E8B-9BB5-76283379BA3F}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(NestedProjects) = preSolution
|
GlobalSection(NestedProjects) = preSolution
|
||||||
{5AFB6255-CF1B-4660-BB35-F24C8C75FECE} = {503DDD6B-BE10-4235-9EBD-E9B1FA6067DF}
|
{5AFB6255-CF1B-4660-BB35-F24C8C75FECE} = {503DDD6B-BE10-4235-9EBD-E9B1FA6067DF}
|
||||||
{830F5A71-0192-4288-9F4D-D7849D958970} = {503DDD6B-BE10-4235-9EBD-E9B1FA6067DF}
|
{830F5A71-0192-4288-9F4D-D7849D958970} = {503DDD6B-BE10-4235-9EBD-E9B1FA6067DF}
|
||||||
{87DABC88-C38C-45DB-8F72-53B7C95ABC89} = {503DDD6B-BE10-4235-9EBD-E9B1FA6067DF}
|
{87DABC88-C38C-45DB-8F72-53B7C95ABC89} = {503DDD6B-BE10-4235-9EBD-E9B1FA6067DF}
|
||||||
{38AA74FE-3932-49C3-A382-338E7C861BB1} = {503DDD6B-BE10-4235-9EBD-E9B1FA6067DF}
|
{38AA74FE-3932-49C3-A382-338E7C861BB1} = {503DDD6B-BE10-4235-9EBD-E9B1FA6067DF}
|
||||||
|
{16CCC793-BF57-4E8B-9BB5-76283379BA3F} = {503DDD6B-BE10-4235-9EBD-E9B1FA6067DF}
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
EndGlobal
|
EndGlobal
|
||||||
|
Reference in New Issue
Block a user