mirror of
https://git.teknik.io/Teknikode/Teknik.git
synced 2023-08-02 14:16:22 +02:00
Added customization of scopes and grant type for clients
This commit is contained in:
parent
d47b5e5785
commit
94be2cf236
@ -542,19 +542,15 @@ namespace Teknik.IdentityServer.Controllers
|
||||
ClientName = model.Name,
|
||||
ClientUri = model.HomepageUrl,
|
||||
LogoUri = model.LogoUrl,
|
||||
AllowedGrantTypes = new List<string>()
|
||||
{
|
||||
GrantType.AuthorizationCode,
|
||||
GrantType.ClientCredentials
|
||||
},
|
||||
|
||||
AllowedGrantTypes = model.AllowedGrants,
|
||||
AllowedScopes = model.AllowedScopes,
|
||||
|
||||
ClientSecrets =
|
||||
{
|
||||
new IdentityServer4.Models.Secret(clientSecret.Sha256())
|
||||
},
|
||||
|
||||
RequireConsent = true,
|
||||
|
||||
RedirectUris =
|
||||
{
|
||||
model.CallbackUrl
|
||||
@ -565,8 +561,7 @@ namespace Teknik.IdentityServer.Controllers
|
||||
origin
|
||||
},
|
||||
|
||||
AllowedScopes = model.AllowedScopes,
|
||||
|
||||
RequireConsent = true,
|
||||
AllowOfflineAccess = true
|
||||
};
|
||||
|
||||
@ -617,6 +612,36 @@ namespace Teknik.IdentityServer.Controllers
|
||||
newOrigin.Origin = origin;
|
||||
configContext.Add(newUri);
|
||||
|
||||
// Update their allowed grants
|
||||
var curGrants = configContext.Set<ClientGrantType>().Where(c => c.ClientId == foundClient.Id).ToList();
|
||||
if (curGrants != null)
|
||||
{
|
||||
configContext.RemoveRange(curGrants);
|
||||
}
|
||||
foreach (var grantType in model.AllowedGrants)
|
||||
{
|
||||
var newGrant = new ClientGrantType();
|
||||
newGrant.Client = foundClient;
|
||||
newGrant.ClientId = foundClient.Id;
|
||||
newGrant.GrantType = grantType;
|
||||
configContext.Add(newGrant);
|
||||
}
|
||||
|
||||
// Update their allowed scopes
|
||||
var curScopes = configContext.Set<ClientScope>().Where(c => c.ClientId == foundClient.Id).ToList();
|
||||
if (curScopes != null)
|
||||
{
|
||||
configContext.RemoveRange(curScopes);
|
||||
}
|
||||
foreach (var scope in model.AllowedScopes)
|
||||
{
|
||||
var newScope = new ClientScope();
|
||||
newScope.Client = foundClient;
|
||||
newScope.ClientId = foundClient.Id;
|
||||
newScope.Scope = scope;
|
||||
configContext.Add(newScope);
|
||||
}
|
||||
|
||||
// Save all the changed
|
||||
configContext.SaveChanges();
|
||||
|
||||
|
@ -13,5 +13,6 @@ namespace Teknik.IdentityServer.Models.Manage
|
||||
public string LogoUrl { get; set; }
|
||||
public string CallbackUrl { get; set; }
|
||||
public ICollection<string> AllowedScopes { get; set; }
|
||||
public ICollection<string> AllowedGrants { get; set; }
|
||||
}
|
||||
}
|
||||
|
@ -13,5 +13,7 @@ namespace Teknik.IdentityServer.Models.Manage
|
||||
public string HomepageUrl { get; set; }
|
||||
public string LogoUrl { get; set; }
|
||||
public string CallbackUrl { get; set; }
|
||||
public ICollection<string> AllowedScopes { get; set; }
|
||||
public ICollection<string> AllowedGrants { get; set; }
|
||||
}
|
||||
}
|
||||
|
@ -21,7 +21,7 @@
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||
},
|
||||
"applicationUrl": "https://localhost:6002/"
|
||||
"applicationUrl": "https://localhost:9002/"
|
||||
},
|
||||
"IdentityServer - Prod": {
|
||||
"commandName": "Project",
|
||||
@ -29,7 +29,7 @@
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Production"
|
||||
},
|
||||
"applicationUrl": "https://localhost:6002/"
|
||||
"applicationUrl": "https://localhost:9002/"
|
||||
}
|
||||
}
|
||||
}
|
@ -18,7 +18,6 @@
|
||||
<div class="form-group">
|
||||
<label asp-for="TwoFactorCode"></label>
|
||||
<input asp-for="TwoFactorCode" class="form-control" autocomplete="off" />
|
||||
<span asp-validation-for="TwoFactorCode" class="text-danger"></span>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div class="abc-checkbox">
|
||||
|
@ -20,7 +20,6 @@
|
||||
<div class="form-group">
|
||||
<label asp-for="RecoveryCode"></label>
|
||||
<input asp-for="RecoveryCode" class="form-control" autocomplete="off" />
|
||||
<span asp-validation-for="RecoveryCode" class="text-danger"></span>
|
||||
</div>
|
||||
<button type="submit" class="btn btn-default pull-right">Log in</button>
|
||||
</form>
|
||||
|
@ -437,7 +437,8 @@ namespace Teknik.Areas.Users.Controllers
|
||||
HomepageUrl = client.ClientUri,
|
||||
LogoUrl = client.LogoUri,
|
||||
CallbackUrl = string.Join(',', client.RedirectUris),
|
||||
AllowedScopes = client.AllowedScopes
|
||||
AllowedScopes = client.AllowedScopes,
|
||||
GrantType = IdentityHelper.GrantsToGrantType(client.AllowedGrantTypes.ToArray())
|
||||
});
|
||||
}
|
||||
|
||||
@ -1239,7 +1240,7 @@ namespace Teknik.Areas.Users.Controllers
|
||||
|
||||
[HttpPost]
|
||||
[ValidateAntiForgeryToken]
|
||||
public async Task<IActionResult> CreateClient(string name, string homepageUrl, string logoUrl, string callbackUrl, [FromServices] ICompositeViewEngine viewEngine)
|
||||
public async Task<IActionResult> CreateClient(string name, string homepageUrl, string logoUrl, string callbackUrl, IdentityClientGrant grantType, string scopes, [FromServices] ICompositeViewEngine viewEngine)
|
||||
{
|
||||
try
|
||||
{
|
||||
@ -1255,7 +1256,15 @@ namespace Teknik.Areas.Users.Controllers
|
||||
return Json(new { error = "Invalid logo URL" });
|
||||
|
||||
// Validate the code with the identity server
|
||||
var result = await IdentityHelper.CreateClient(_config, User.Identity.Name, name, homepageUrl, logoUrl, callbackUrl, "openid", "role", "account-info", "security-info", "teknik-api.read", "teknik-api.write");
|
||||
var result = await IdentityHelper.CreateClient(
|
||||
_config,
|
||||
User.Identity.Name,
|
||||
name,
|
||||
homepageUrl,
|
||||
logoUrl,
|
||||
callbackUrl,
|
||||
IdentityHelper.GrantTypeToGrants(grantType),
|
||||
scopes.Split(','));
|
||||
|
||||
if (result.Success)
|
||||
{
|
||||
@ -1267,6 +1276,8 @@ namespace Teknik.Areas.Users.Controllers
|
||||
model.HomepageUrl = homepageUrl;
|
||||
model.LogoUrl = logoUrl;
|
||||
model.CallbackUrl = callbackUrl;
|
||||
model.GrantType = grantType;
|
||||
model.AllowedScopes = scopes.Split(',');
|
||||
|
||||
string renderedView = await RenderPartialViewToString(viewEngine, "~/Areas/User/Views/User/Settings/ClientView.cshtml", model);
|
||||
|
||||
@ -1287,14 +1298,15 @@ namespace Teknik.Areas.Users.Controllers
|
||||
Client foundClient = await IdentityHelper.GetClient(_config, User.Identity.Name, clientId);
|
||||
if (foundClient != null)
|
||||
{
|
||||
ClientViewModel model = new ClientViewModel()
|
||||
ClientModifyViewModel model = new ClientModifyViewModel()
|
||||
{
|
||||
Id = foundClient.ClientId,
|
||||
Name = foundClient.ClientName,
|
||||
HomepageUrl = foundClient.ClientUri,
|
||||
LogoUrl = foundClient.LogoUri,
|
||||
CallbackUrl = string.Join(',', foundClient.RedirectUris),
|
||||
AllowedScopes = foundClient.AllowedScopes
|
||||
AllowedScopes = foundClient.AllowedScopes,
|
||||
GrantType = IdentityHelper.GrantsToGrantType(foundClient.AllowedGrantTypes.ToArray()).ToString()
|
||||
};
|
||||
|
||||
return Json(new { result = true, client = model });
|
||||
@ -1304,7 +1316,7 @@ namespace Teknik.Areas.Users.Controllers
|
||||
|
||||
[HttpPost]
|
||||
[ValidateAntiForgeryToken]
|
||||
public async Task<IActionResult> EditClient(string clientId, string name, string homepageUrl, string logoUrl, string callbackUrl, [FromServices] ICompositeViewEngine viewEngine)
|
||||
public async Task<IActionResult> EditClient(string clientId, string name, string homepageUrl, string logoUrl, string callbackUrl, IdentityClientGrant grantType, string scopes, [FromServices] ICompositeViewEngine viewEngine)
|
||||
{
|
||||
try
|
||||
{
|
||||
@ -1325,7 +1337,16 @@ namespace Teknik.Areas.Users.Controllers
|
||||
return Json(new { error = "Client does not exist" });
|
||||
|
||||
// Validate the code with the identity server
|
||||
var result = await IdentityHelper.EditClient(_config, User.Identity.Name, clientId, name, homepageUrl, logoUrl, callbackUrl);
|
||||
var result = await IdentityHelper.EditClient(
|
||||
_config,
|
||||
User.Identity.Name,
|
||||
clientId,
|
||||
name,
|
||||
homepageUrl,
|
||||
logoUrl,
|
||||
callbackUrl,
|
||||
IdentityHelper.GrantTypeToGrants(grantType),
|
||||
scopes.Split(','));
|
||||
|
||||
if (result.Success)
|
||||
{
|
||||
@ -1337,6 +1358,8 @@ namespace Teknik.Areas.Users.Controllers
|
||||
model.HomepageUrl = homepageUrl;
|
||||
model.LogoUrl = logoUrl;
|
||||
model.CallbackUrl = callbackUrl;
|
||||
model.GrantType = grantType;
|
||||
model.AllowedScopes = scopes.Split(',');
|
||||
|
||||
string renderedView = await RenderPartialViewToString(viewEngine, "~/Areas/User/Views/User/Settings/ClientView.cshtml", model);
|
||||
|
||||
|
@ -71,6 +71,47 @@ namespace Teknik.Areas.Users.Utility
|
||||
return new IdentityResult() { Success = false, Message = "HTTP Error: " + response.StatusCode + " | " + (await response.Content.ReadAsStringAsync()) };
|
||||
}
|
||||
|
||||
public static string[] GrantTypeToGrants(IdentityClientGrant grantType)
|
||||
{
|
||||
List<string> grants = new List<string>();
|
||||
switch (grantType)
|
||||
{
|
||||
case IdentityClientGrant.Implicit:
|
||||
grants.Add(GrantType.Implicit);
|
||||
break;
|
||||
case IdentityClientGrant.AuthorizationCode:
|
||||
grants.Add(GrantType.AuthorizationCode);
|
||||
break;
|
||||
case IdentityClientGrant.ClientCredentials:
|
||||
grants.Add(GrantType.ClientCredentials);
|
||||
break;
|
||||
default:
|
||||
grants.Add(GrantType.Hybrid);
|
||||
break;
|
||||
}
|
||||
return grants.ToArray();
|
||||
}
|
||||
|
||||
public static IdentityClientGrant GrantsToGrantType(string[] grants)
|
||||
{
|
||||
if (grants.Contains(GrantType.Implicit))
|
||||
{
|
||||
return IdentityClientGrant.Implicit;
|
||||
}
|
||||
else if (grants.Contains(GrantType.AuthorizationCode))
|
||||
{
|
||||
return IdentityClientGrant.AuthorizationCode;
|
||||
}
|
||||
else if (grants.Contains(GrantType.ClientCredentials))
|
||||
{
|
||||
return IdentityClientGrant.ClientCredentials;
|
||||
}
|
||||
else
|
||||
{
|
||||
return IdentityClientGrant.ClientCredentials;
|
||||
}
|
||||
}
|
||||
|
||||
// API Functions
|
||||
|
||||
public static async Task<IdentityResult> CreateUser(Config config, string username, string password, string recoveryEmail)
|
||||
@ -350,7 +391,7 @@ namespace Teknik.Areas.Users.Utility
|
||||
throw new Exception(result.Message);
|
||||
}
|
||||
|
||||
public static async Task<IdentityResult> CreateClient(Config config, string username, string name, string homepageUrl, string logoUrl, string callbackUrl, params string[] allowedScopes)
|
||||
public static async Task<IdentityResult> CreateClient(Config config, string username, string name, string homepageUrl, string logoUrl, string callbackUrl, string[] allowedGrants, string[] allowedScopes)
|
||||
{
|
||||
var manageUrl = CreateUrl(config, $"Manage/CreateClient");
|
||||
|
||||
@ -362,12 +403,13 @@ namespace Teknik.Areas.Users.Utility
|
||||
homepageUrl = homepageUrl,
|
||||
logoUrl = logoUrl,
|
||||
callbackUrl = callbackUrl,
|
||||
allowedScopes = allowedScopes
|
||||
allowedScopes = allowedScopes,
|
||||
allowedGrants = allowedGrants
|
||||
});
|
||||
return response;
|
||||
}
|
||||
|
||||
public static async Task<IdentityResult> EditClient(Config config, string username, string clientId, string name, string homepageUrl, string logoUrl, string callbackUrl)
|
||||
public static async Task<IdentityResult> EditClient(Config config, string username, string clientId, string name, string homepageUrl, string logoUrl, string callbackUrl, string[] allowedGrants, string[] allowedScopes)
|
||||
{
|
||||
var manageUrl = CreateUrl(config, $"Manage/EditClient");
|
||||
|
||||
@ -379,7 +421,9 @@ namespace Teknik.Areas.Users.Utility
|
||||
name = name,
|
||||
homepageUrl = homepageUrl,
|
||||
logoUrl = logoUrl,
|
||||
callbackUrl = callbackUrl
|
||||
callbackUrl = callbackUrl,
|
||||
allowedScopes = allowedScopes,
|
||||
allowedGrants = allowedGrants
|
||||
});
|
||||
return response;
|
||||
}
|
||||
|
20
Teknik/Areas/User/ViewModels/ClientModifyViewModel.cs
Normal file
20
Teknik/Areas/User/ViewModels/ClientModifyViewModel.cs
Normal file
@ -0,0 +1,20 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Teknik.Utilities;
|
||||
using Teknik.ViewModels;
|
||||
|
||||
namespace Teknik.Areas.Users.ViewModels
|
||||
{
|
||||
public class ClientModifyViewModel : ViewModelBase
|
||||
{
|
||||
public string Id { get; set; }
|
||||
public string Name { get; set; }
|
||||
public string HomepageUrl { get; set; }
|
||||
public string LogoUrl { get; set; }
|
||||
public string CallbackUrl { get; set; }
|
||||
public ICollection<string> AllowedScopes { get; set; }
|
||||
public string GrantType { get; set; }
|
||||
}
|
||||
}
|
@ -2,6 +2,7 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Teknik.Utilities;
|
||||
using Teknik.ViewModels;
|
||||
|
||||
namespace Teknik.Areas.Users.ViewModels
|
||||
@ -14,5 +15,6 @@ namespace Teknik.Areas.Users.ViewModels
|
||||
public string LogoUrl { get; set; }
|
||||
public string CallbackUrl { get; set; }
|
||||
public ICollection<string> AllowedScopes { get; set; }
|
||||
public IdentityClientGrant GrantType { get; set; }
|
||||
}
|
||||
}
|
||||
|
@ -27,6 +27,33 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm-4">
|
||||
<div class="row">
|
||||
<div class="col-sm-12">
|
||||
<strong>Allowed Scopes</strong>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-sm-12">
|
||||
@(string.Join(", ", Model.AllowedScopes))
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm-4">
|
||||
<div class="row">
|
||||
<div class="col-sm-12">
|
||||
<strong>Grant Type</strong>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-sm-12">
|
||||
@Model.GrantType.GetDescription()
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<br />
|
||||
<div class="row">
|
||||
<div class="col-sm-4">
|
||||
<div class="row">
|
||||
<div class="col-sm-12">
|
||||
@ -39,7 +66,7 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm-4">
|
||||
<div class="col-sm-8">
|
||||
<div class="row">
|
||||
<div class="col-sm-12">
|
||||
<strong>Authorization Callback Url</strong>
|
||||
|
@ -6,6 +6,8 @@
|
||||
Layout = "~/Areas/User/Views/User/Settings/Settings.cshtml";
|
||||
}
|
||||
|
||||
<bundle src="css/user.settings.developer.min.css" append-version="true"></bundle>
|
||||
|
||||
<script>
|
||||
var createClientURL = '@Url.SubRouteUrl("account", "User.Action", new { action = "CreateClient" })';
|
||||
var editClientURL = '@Url.SubRouteUrl("account", "User.Action", new { action = "EditClient" })';
|
||||
@ -79,6 +81,47 @@
|
||||
<label for="clientCallbackUrl">Authorization callback URL <span class="text-danger">*</span></label>
|
||||
<input type="text" class="form-control" id="clientCallbackUrl" name="clientCallbackUrl" data-val-required="The Authorization callback URL field is required." data-val="true" />
|
||||
</div>
|
||||
<div class="form-group" id="grantSection">
|
||||
<label for="grantType">Grant Type</label>
|
||||
<select class="form-control" name="grantType" id="grantType">
|
||||
@foreach (IdentityClientGrant grant in Enum.GetValues(typeof(IdentityClientGrant)))
|
||||
{
|
||||
<!option value="@grant">@grant.GetDescription()</!option>
|
||||
}
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-group" id="scopeSection">
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<span class="glyphicon glyphicon-tasks"></span>
|
||||
Allowed Scopes
|
||||
</div>
|
||||
<ul class="list-group">
|
||||
@foreach (IdentityClientScope scope in Enum.GetValues(typeof(IdentityClientScope)))
|
||||
{
|
||||
|
||||
<li class="list-group-item abc-checkbox">
|
||||
<input class="consent-scopecheck @(scope.IsReadOnly() ? "default" : string.Empty)"
|
||||
type="checkbox"
|
||||
name="allowedScope"
|
||||
id="scopes_@scope.GetDisplayName()"
|
||||
value="@scope.GetDisplayName()"
|
||||
checked="@scope.IsReadOnly()"
|
||||
disabled="@scope.IsReadOnly()" />
|
||||
<label for="ScopesConsented">
|
||||
<strong>@scope.GetDisplayName()</strong>
|
||||
</label>
|
||||
@if (!string.IsNullOrEmpty(scope.GetDescription()))
|
||||
{
|
||||
<div class="consent-description">
|
||||
<label for="scopes_@scope.GetDisplayName()">@scope.GetDescription()</label>
|
||||
</div>
|
||||
}
|
||||
</li>
|
||||
}
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-sm-12">
|
||||
<button class="btn btn-primary pull-right hidden clientSubmit" id="clientCreateSubmit" type="submit" name="clientCreateSubmit">Create Client</button>
|
||||
|
12
Teknik/Content/User/Settings/Developer.css
Normal file
12
Teknik/Content/User/Settings/Developer.css
Normal file
@ -0,0 +1,12 @@
|
||||
.consent-scopecheck {
|
||||
display: inline-block;
|
||||
margin-right: 5px;
|
||||
}
|
||||
|
||||
.consent-description {
|
||||
margin-left: 25px;
|
||||
}
|
||||
|
||||
.consent-description label {
|
||||
font-weight: normal;
|
||||
}
|
@ -25,6 +25,11 @@ $(document).ready(function () {
|
||||
$("#createClient").click(function () {
|
||||
$('#clientModal').find('#clientCreateSubmit').removeClass('hidden');
|
||||
$('#clientModal').find('#clientCreateSubmit').text('Create Client');
|
||||
_.forEach($('#clientModal').find('#scopeSection :checkbox'), function (cb) {
|
||||
if ($(cb).hasClass('default')) {
|
||||
$(cb).prop('checked', true);
|
||||
}
|
||||
});
|
||||
|
||||
$('#clientModal').modal('show');
|
||||
});
|
||||
@ -101,6 +106,11 @@ function editClient(clientId) {
|
||||
$('#clientModal').find('#clientHomepageUrl').val(data.client.homepageUrl);
|
||||
$('#clientModal').find('#clientLogoUrl').val(data.client.logoUrl);
|
||||
$('#clientModal').find('#clientCallbackUrl').val(data.client.callbackUrl);
|
||||
$('#clientModal').find('#grantType').val(data.client.grantType);
|
||||
|
||||
_.forEach(data.client.allowedScopes, function (scope) {
|
||||
$('#clientModal').find('#scopes_' + scope).prop('checked', true);
|
||||
});
|
||||
|
||||
$('#clientModal').find('#clientEditSubmit').removeClass('hidden');
|
||||
$('#clientModal').find('#clientEditSubmit').text('Save Client');
|
||||
@ -168,7 +178,7 @@ function deleteClient(clientId) {
|
||||
}
|
||||
|
||||
function saveClientInfo(url, submitText, submitActionText, callback) {
|
||||
var clientId, name, homepageUrl, logoUrl, callbackUrl;
|
||||
var clientId, name, homepageUrl, logoUrl, callbackUrl, grantType, scopes;
|
||||
disableButton('.clientSubmit', submitActionText);
|
||||
|
||||
clientId = $('#clientModal').find('#clientId').val();
|
||||
@ -176,11 +186,17 @@ function saveClientInfo(url, submitText, submitActionText, callback) {
|
||||
homepageUrl = $('#clientModal').find('#clientHomepageUrl').val();
|
||||
logoUrl = $('#clientModal').find('#clientLogoUrl').val();
|
||||
callbackUrl = $('#clientModal').find('#clientCallbackUrl').val();
|
||||
grantType = $('#clientModal').find('#grantType').val();
|
||||
scopes = $('#clientModal').find('#scopeSection :checkbox:checked');
|
||||
scopes = _.map(scopes, function (cb) {
|
||||
return cb.value;
|
||||
});
|
||||
scopes = scopes.join(',');
|
||||
|
||||
$.ajax({
|
||||
type: "POST",
|
||||
url: url,
|
||||
data: AddAntiForgeryToken({ clientId: clientId, name: name, homepageUrl: homepageUrl, logoUrl: logoUrl, callbackUrl: callbackUrl }),
|
||||
data: AddAntiForgeryToken({ clientId: clientId, name: name, homepageUrl: homepageUrl, logoUrl: logoUrl, callbackUrl: callbackUrl, grantType: grantType, scopes: scopes }),
|
||||
success: function (response) {
|
||||
if (response.result) {
|
||||
if (callback) {
|
||||
|
@ -155,6 +155,9 @@ function clearInputs(parent) {
|
||||
$(parent).find('textarea').each(function () {
|
||||
$(this).val('');
|
||||
});
|
||||
$(parent).find('input:checkbox').each(function () {
|
||||
$(this).prop('checked', false);
|
||||
});
|
||||
}
|
||||
|
||||
String.prototype.hashCode = function () {
|
||||
|
@ -263,6 +263,12 @@
|
||||
"./wwwroot/js/app/User/DeveloperSettings.js"
|
||||
]
|
||||
},
|
||||
{
|
||||
"outputFileName": "./wwwroot/css/user.settings.developer.min.css",
|
||||
"inputFiles": [
|
||||
"./wwwroot/css/app/User/Settings/Developer.css"
|
||||
]
|
||||
},
|
||||
{
|
||||
"outputFileName": "./wwwroot/js/user.settings.upload.min.js",
|
||||
"inputFiles": [
|
||||
|
54
Utilities/Extensions.cs
Normal file
54
Utilities/Extensions.cs
Normal file
@ -0,0 +1,54 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
|
||||
namespace Teknik.Utilities
|
||||
{
|
||||
public static class Extensions
|
||||
{
|
||||
public static string GetDescription<T>(this T value)
|
||||
{
|
||||
FieldInfo fi = value.GetType().GetField(value.ToString());
|
||||
|
||||
DescriptionAttribute[] attributes = fi.GetCustomAttributes(typeof(DescriptionAttribute), false) as DescriptionAttribute[];
|
||||
|
||||
if (attributes != null && attributes.Any())
|
||||
{
|
||||
return attributes.First().Description;
|
||||
}
|
||||
|
||||
return value.ToString();
|
||||
}
|
||||
|
||||
public static string GetDisplayName<T>(this T value)
|
||||
{
|
||||
FieldInfo fi = value.GetType().GetField(value.ToString());
|
||||
|
||||
DisplayNameAttribute[] attributes = fi.GetCustomAttributes(typeof(DisplayNameAttribute), false) as DisplayNameAttribute[];
|
||||
|
||||
if (attributes != null && attributes.Any())
|
||||
{
|
||||
return attributes.First().DisplayName;
|
||||
}
|
||||
|
||||
return value.ToString();
|
||||
}
|
||||
|
||||
public static bool IsReadOnly<T>(this T value)
|
||||
{
|
||||
FieldInfo fi = value.GetType().GetField(value.ToString());
|
||||
|
||||
ReadOnlyAttribute[] attributes = fi.GetCustomAttributes(typeof(ReadOnlyAttribute), false) as ReadOnlyAttribute[];
|
||||
|
||||
if (attributes != null && attributes.Any())
|
||||
{
|
||||
return attributes.First().IsReadOnly;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
17
Utilities/IdentityClientGrant.cs
Normal file
17
Utilities/IdentityClientGrant.cs
Normal file
@ -0,0 +1,17 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Text;
|
||||
|
||||
namespace Teknik.Utilities
|
||||
{
|
||||
public enum IdentityClientGrant
|
||||
{
|
||||
[Description("Authorization Code")]
|
||||
AuthorizationCode,
|
||||
[Description("Client Credentials")]
|
||||
ClientCredentials,
|
||||
[Description("Implicit")]
|
||||
Implicit,
|
||||
}
|
||||
}
|
30
Utilities/IdentityClientScope.cs
Normal file
30
Utilities/IdentityClientScope.cs
Normal file
@ -0,0 +1,30 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Text;
|
||||
|
||||
namespace Teknik.Utilities
|
||||
{
|
||||
public enum IdentityClientScope
|
||||
{
|
||||
[DisplayName("openid")]
|
||||
[Description("The user identifier")]
|
||||
[ReadOnly(true)]
|
||||
openid,
|
||||
[DisplayName("role")]
|
||||
[Description("The user role")]
|
||||
role,
|
||||
[DisplayName("account-info")]
|
||||
[Description("A user's account information")]
|
||||
accountInfo,
|
||||
[DisplayName("security-info")]
|
||||
[Description("A user's security information")]
|
||||
securityInfo,
|
||||
[DisplayName("teknik-api.read")]
|
||||
[Description("Read access to the Teknik API")]
|
||||
teknikApiRead,
|
||||
[DisplayName("teknik-api.write")]
|
||||
[Description("Write access to the Teknik API")]
|
||||
teknikApiWrite,
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user