ABP框架使用(版本3.3.1) - IdentityServer


1.IdentityServerClientScopes 分配的Scope太多,会报错

“Scope parameter exceeds max allowed length”

在Domain.Shared层改MyAppModuleExtensionConfigurator可以改abp identityserver定义的const值

private static void ConfigureExistingProperties()
{
  ClientScopeConsts.ScopeMaxLength = 1000;
} 

这表里面字段长度,而Scope parameter validation是identityserver4的包里做的,这样改并没有效果

应该在Host层改变IdentityServerOptions , PreConfigureServices 和 PostConfigureServices 都可以

public override void PostConfigureServices(ServiceConfigurationContext context)
        {
            PostConfigure<IdentityServerOptions>(options =>
            {
                options.InputLengthRestrictions.Scope = 2000;
            });    
        }

 

2.How to integrate Identity Server with Active Directory #2636
https://github.com/abpframework/abp/issues/2636

 context.Services.Replace(ServiceDescriptor
     .Transient<UserManager<IdentityUser>, LdapUserManager<IdentityUser>>());
public class LdapUserManager<TUser> : Microsoft.AspNetCore.Identity.UserManager<TUser>
       where TUser : IdentityUser
   {
       private readonly IEventService _events;
       private readonly ILdapManager _ldapManager;
       private readonly AbpLdapOptions _ldapOptions;

       public LdapUserManager(
           IUserStore<TUser> store, IOptions<IdentityOptions> optionsAccessor, IPasswordHasher<TUser> passwordHasher,
           IEnumerable<IUserValidator<TUser>> userValidators,
           IEnumerable<IPasswordValidator<TUser>> passwordValidators, ILookupNormalizer keyNormalizer,
           IdentityErrorDescriber errors, IServiceProvider services, ILogger<UserManager<TUser>> logger,
           IEventService events,
           ILdapManager ldapManager,
           IOptions<AbpLdapOptions> ldapOptions
       ) : base(
           store, optionsAccessor, passwordHasher, userValidators, passwordValidators, keyNormalizer, errors, services,
           logger
       )
       {
           _events = events;
           _ldapManager = ldapManager;
           _ldapOptions = ldapOptions.Value;
       }

       public override async Task<bool> CheckPasswordAsync(TUser user, string password)
       {
           if (string.IsNullOrEmpty(_ldapOptions.DomainName))
           {
               throw new InvalidOperationException("The LDAP Hostname cannot be empty or null.");
           }

           if (string.IsNullOrEmpty(password) || string.IsNullOrEmpty(user.UserName))
           {
               throw new InvalidOperationException("The LDAP User and Password cannot be empty or null.");
           }

           var userName = string.IsNullOrWhiteSpace(_ldapOptions.DomainName)
               ? user.UserName
               : $"{user.UserName}@{_ldapOptions.DomainName}";

           var success = _ldapManager.Authenticate(userName, password);
           if (success)
           {
               Logger.LogInformation("Credentials validated for username: {username}", userName);
               await _events.RaiseAsync(new UserLoginSuccessEvent(userName, user.Id.ToString(), userName,
                   interactive: false));
               return true;
           }

           Logger.LogInformation("Authentication failed for username: {username}, reason: invalid credentials",
               userName);
           await _events.RaiseAsync(new UserLoginFailureEvent(userName, "invalid credentials",
               interactive: false));
           return false;
       }
//...
}

3. Identity 接口

IIdentityServerInteractionService:用户交互相关接口

IResourceStore:获取资源接口:这里包括2中资源 一种是IdentityResource 和 ApiResource

IClientStore:获取客户端相关接口

IEventService:事件服务

UserStoreServices:自定义的用户服务,这里我没有用IdentityServer4的TestUserStore是为了方面自定义处理

4.证书 参考

IdentityServer4环境部署失败分析贴(一)

https://www.cnblogs.com/Imaigne/p/10519493.html

//在正式环境中,这可能会报错
builder.AddDeveloperSigningCredential(true, "tempkey.rsa");

//正确方式
builder.AddSigningCredential(new X509Certificate2(path,
                         Configuration["Certificates:Password"]))
这里可以参见郭的随笔:
https://www.cnblogs.com/guolianyu/p/9872661.html        

5.JWT与Reference Token的区别

IdentityServer4之JWT签名(RSA加密证书)及验签
https://www.cnblogs.com/guolianyu/p/9872661.html

6.OIDC

[认证 & 授权] 4. OIDC(OpenId Connect)身份认证(核心部分)

https://www.cnblogs.com/linianhui/p/openid-connect-core.html#auto-id-0

https://github.com/solenovex/Identity-Server-4-Tutorial-Demo-Code

 7.Oauth2.0

OAuth2.0 知多少

https://www.cnblogs.com/sheng-jie/p/6564520.html

8.自定义登录认证,在domain层override IResourceOwnerPasswordValidator 的 ValidateAsync 方法

用 SignInManager.SignInWithClaimsAsync 可以加 Customer Claims

 

using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Claims;
using System.Threading.Tasks;
using IdentityModel;
using IdentityServer4.AspNetIdentity;
using IdentityServer4.Events;
using IdentityServer4.Models;
using IdentityServer4.Services;
using IdentityServer4.Validation;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Identity;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Localization;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Identity;
using Volo.Abp.IdentityServer.Localization;
using Volo.Abp.Security.Claims;
using Volo.Abp.Uow;
using Volo.Abp.Validation;
using IdentityUser = Volo.Abp.Identity.IdentityUser;

namespace Volo.Abp.IdentityServer.AspNetIdentity
{
    [Dependency(ReplaceServices = true)]
    public class MyAbpResourceOwnerPasswordValidator : IResourceOwnerPasswordValidator, ITransientDependency
    {
        protected SignInManager<IdentityUser> SignInManager { get; }
        protected UserManager<IdentityUser> UserManager { get; }
        protected IdentitySecurityLogManager IdentitySecurityLogManager { get; }
        protected ILogger<ResourceOwnerPasswordValidator<IdentityUser>> Logger { get; }
        protected IStringLocalizer<AbpIdentityServerResource> Localizer { get; }
        protected IHybridServiceScopeFactory ServiceScopeFactory { get; }
        protected AbpIdentityOptions AbpIdentityOptions { get; }

        public MyAbpResourceOwnerPasswordValidator(
            UserManager<IdentityUser> userManager,
            SignInManager<IdentityUser> signInManager,
            IdentitySecurityLogManager identitySecurityLogManager,
            ILogger<ResourceOwnerPasswordValidator<IdentityUser>> logger,
            IStringLocalizer<AbpIdentityServerResource> localizer,
            IOptions<AbpIdentityOptions> abpIdentityOptions,
            IHybridServiceScopeFactory serviceScopeFactory)
        {
            UserManager = userManager;
            SignInManager = signInManager;
            IdentitySecurityLogManager = identitySecurityLogManager;
            Logger = logger;
            Localizer = localizer;
            ServiceScopeFactory = serviceScopeFactory;
            AbpIdentityOptions = abpIdentityOptions.Value;
        }

        /// <summary>
        /// https://github.com/IdentityServer/IdentityServer4/blob/master/src/AspNetIdentity/src/ResourceOwnerPasswordValidator.cs#L53
        /// </summary>
        /// <param name="context"></param>
        /// <returns></returns>
        [UnitOfWork]
        public virtual async Task ValidateAsync(ResourceOwnerPasswordValidationContext context)
        {
            var clientId = context.Request?.Client?.ClientId;
            using var scope = ServiceScopeFactory.CreateScope();

            await ReplaceEmailToUsernameOfInputIfNeeds(context);

            IdentityUser user = null;
            var additionalClaims = new List<Claim>();
            

            async Task SetSuccessResultAsync()
            {
                var sub = await UserManager.GetUserIdAsync(user);

                Logger.LogInformation("Credentials validated for username: {username}", context.UserName);

                

                await AddCustomClaimsAsync(additionalClaims, user, context);

                await SignInManager.SignInWithClaimsAsync(user, new AuthenticationProperties { IsPersistent = true }, additionalClaims);

                context.Result = new GrantValidationResult(
                    sub,
                    OidcConstants.AuthenticationMethods.Password,
                    additionalClaims.ToArray()
                );

                await IdentitySecurityLogManager.SaveAsync(
                    new IdentitySecurityLogContext
                    {
                        Identity = IdentityServerSecurityLogIdentityConsts.IdentityServer,
                        Action = IdentityServerSecurityLogActionConsts.LoginSucceeded,
                        UserName = context.UserName,
                        ClientId = clientId
                        
                    }
                );
            }
          
            if (AbpIdentityOptions.ExternalLoginProviders.Any())
            {
                foreach (var externalLoginProviderInfo in AbpIdentityOptions.ExternalLoginProviders.Values)
                {
                    var externalLoginProvider = (IExternalLoginProvider)scope.ServiceProvider
                        .GetRequiredService(externalLoginProviderInfo.Type);

                    if (await externalLoginProvider.TryAuthenticateAsync(context.UserName, context.Password))
                    {
                        user = await UserManager.FindByNameAsync(context.UserName);
                        if (user == null)
                        {
                            user = await externalLoginProvider.CreateUserAsync(context.UserName, externalLoginProviderInfo.Name);
                        }
                        else
                        {
                            await externalLoginProvider.UpdateUserAsync(user, externalLoginProviderInfo.Name);
                        }

                        await SetSuccessResultAsync();
                        return;
                    }
                }
            }

            user = await UserManager.FindByNameAsync(context.UserName);
            string errorDescription = string.Empty;
            if (user != null)
            {
                AuthenticationProperties auth = new AuthenticationProperties();
                 var result = await SignInManager.CheckPasswordSignInAsync(user, context.Password, true);

                if (result.Succeeded)
                {
                    await SetSuccessResultAsync();
                    return;
                }
                else if (result.IsLockedOut)
                {
                    Logger.LogInformation("Authentication failed for username: {username}, reason: locked out", context.UserName);
                    errorDescription = Localizer["UserLockedOut"];
                }
                else if (result.IsNotAllowed)
                {
                    Logger.LogInformation("Authentication failed for username: {username}, reason: not allowed", context.UserName);
                    errorDescription = Localizer["LoginIsNotAllowed"];
                }
                else
                {
                    Logger.LogInformation("Authentication failed for username: {username}, reason: invalid credentials", context.UserName);
                    errorDescription = Localizer["InvalidUserNameOrPassword"];
                }

                await IdentitySecurityLogManager.SaveAsync(new IdentitySecurityLogContext
                {
                    Identity = IdentityServerSecurityLogIdentityConsts.IdentityServer,
                    Action = result.ToIdentitySecurityLogAction(),
                    UserName = context.UserName,
                    ClientId = clientId
                });
                await SetSuccessResultAsync();
                 return;
            }
            else
            {
                Logger.LogInformation("No user found matching username: {username}", context.UserName);
                errorDescription = Localizer["InvalidUsername"];

                await IdentitySecurityLogManager.SaveAsync(new IdentitySecurityLogContext()
                {
                    Identity = IdentityServerSecurityLogIdentityConsts.IdentityServer,
                    Action = IdentityServerSecurityLogActionConsts.LoginInvalidUserName,
                    UserName = context.UserName,
                    ClientId = clientId
                });
            }

            context.Result = new GrantValidationResult(TokenRequestErrors.InvalidGrant, errorDescription);
        }

        protected virtual async Task ReplaceEmailToUsernameOfInputIfNeeds(ResourceOwnerPasswordValidationContext context)
        {
            if (!ValidationHelper.IsValidEmailAddress(context.UserName))
            {
                return;
            }

            var userByUsername = await UserManager.FindByNameAsync(context.UserName);
            if (userByUsername != null)
            {
                return;
            }

            var userByEmail = await UserManager.FindByEmailAsync(context.UserName);
            if (userByEmail == null)
            {
                return;
            }

            context.UserName = userByEmail.UserName;
        }

        protected virtual Task AddCustomClaimsAsync(List<Claim> customClaims, IdentityUser user, ResourceOwnerPasswordValidationContext context)
        {
            if (user.TenantId.HasValue)
            {
                customClaims.Add(new Claim(AbpClaimTypes.TenantId, user.TenantId?.ToString()));
            }
            customClaims.Add(new Claim(AbpClaimTypes.PhoneNumber,"testphone"));
            customClaims.Add(new Claim(JwtClaimTypes.Locale, "testLocale"));
            customClaims.Add(new Claim("testname", "testvalue"));
            return Task.CompletedTask;
        }
    }
}

 

之后在AppService上可以用CurrentUser 获取 Customer Claims

 

 AbpClaimTypes 可以在 configuration api 获取

{{baseUrl}}/api/abp/application-configuration

9. AuthenticationTypes.Federated vs. AuthenticationType Identity.Application

HttpContext.User.Identity.AuthenticationType == "Identity.Application"

 

ClaimsPrincipal principal = new ClaimsPrincipal(new ClaimsIdentity(
            new List<Claim>{
                new Claim(ClaimTypes.Name, username),
                new Claim(PartnersUserDataClaim, userData),
                new Claim(ModuleNameClaim, moduleName)
            },
            "SSO/Windows"));

        await HttpContext.Authentication.SignInAsync(APIAuthSchemeName, principal);

https://github.com/AzureAD/azure-activedirectory-identitymodel-extensions-for-dotnet/blob/dev/src/Microsoft.IdentityModel.Tokens/TokenValidationParameters.cs

然而这种方法我在另一个应用使用却有问题,Claim会被覆盖掉,而 AuthenticationType 是 "AuthenticationTypes.Federation"。

后来注入了AbpUserClaimsPrincipalFactory,还是不行。
然后试着在表 IdentityServerApiResources 把 新加的Claim Name加进去,就可以了。

 

public static readonly string DefaultAuthenticationType = "AuthenticationTypes.Federation";

 

var accessToken = await HttpContext.Authentication.GetTokenAsync("access_token");

 

IdentityServer4-master\IdentityServer4\src\IdentityServer4\src\Services\Default\DefaultClaimsService.cs

// Copyright (c) Brock Allen & Dominick Baier. All rights reserved.
// Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information.


using IdentityModel;
using IdentityServer4.Extensions;
using IdentityServer4.Models;
using IdentityServer4.Validation;
using Microsoft.Extensions.Logging;
using System.Collections.Generic;
using System.Linq;
using System.Security.Claims;
using System.Threading.Tasks;

namespace IdentityServer4.Services
{
    /// <summary>
    /// Default claims provider implementation
    /// </summary>
    public class DefaultClaimsService : IClaimsService
    {
        /// <summary>
        /// The logger
        /// </summary>
        protected readonly ILogger Logger;

        /// <summary>
        /// The user service
        /// </summary>
        protected readonly IProfileService Profile;

        /// <summary>
        /// Initializes a new instance of the <see cref="DefaultClaimsService"/> class.
        /// </summary>
        /// <param name="profile">The profile service</param>
        /// <param name="logger">The logger</param>
        public DefaultClaimsService(IProfileService profile, ILogger<DefaultClaimsService> logger)
        {
            Logger = logger;
            Profile = profile;
        }

        /// <summary>
        /// Returns claims for an identity token
        /// </summary>
        /// <param name="subject">The subject</param>
        /// <param name="resources">The requested resources</param>
        /// <param name="includeAllIdentityClaims">Specifies if all claims should be included in the token, or if the userinfo endpoint can be used to retrieve them</param>
        /// <param name="request">The raw request</param>
        /// <returns>
        /// Claims for the identity token
        /// </returns>
        public virtual async Task<IEnumerable<Claim>> GetIdentityTokenClaimsAsync(ClaimsPrincipal subject, ResourceValidationResult resources, bool includeAllIdentityClaims, ValidatedRequest request)
        {
            Logger.LogDebug("Getting claims for identity token for subject: {subject} and client: {clientId}",
                subject.GetSubjectId(),
                request.Client.ClientId);

            var outputClaims = new List<Claim>(GetStandardSubjectClaims(subject));
            outputClaims.AddRange(GetOptionalClaims(subject));

            // fetch all identity claims that need to go into the id token
            if (includeAllIdentityClaims || request.Client.AlwaysIncludeUserClaimsInIdToken)
            {
                var additionalClaimTypes = new List<string>();

                foreach (var identityResource in resources.Resources.IdentityResources)
                {
                    foreach (var userClaim in identityResource.UserClaims)
                    {
                        additionalClaimTypes.Add(userClaim);
                    }
                }

                // filter so we don't ask for claim types that we will eventually filter out
                additionalClaimTypes = FilterRequestedClaimTypes(additionalClaimTypes).ToList();

                var context = new ProfileDataRequestContext(
                    subject,
                    request.Client,
                    IdentityServerConstants.ProfileDataCallers.ClaimsProviderIdentityToken,
                    additionalClaimTypes)
                {
                    RequestedResources = request.ValidatedResources,
                    ValidatedRequest = request
                };

                await Profile.GetProfileDataAsync(context);

                var claims = FilterProtocolClaims(context.IssuedClaims);
                if (claims != null)
                {
                    outputClaims.AddRange(claims);
                }
            }
            else
            {
                Logger.LogDebug("In addition to an id_token, an access_token was requested. No claims other than sub are included in the id_token. To obtain more user claims, either use the user info endpoint or set AlwaysIncludeUserClaimsInIdToken on the client configuration.");
            }

            return outputClaims;
        }

        /// <summary>
        /// Returns claims for an identity token.
        /// </summary>
        /// <param name="subject">The subject.</param>
        /// <param name="resourceResult">The validated resource result</param>
        /// <param name="request">The raw request.</param>
        /// <returns>
        /// Claims for the access token
        /// </returns>
        public virtual async Task<IEnumerable<Claim>> GetAccessTokenClaimsAsync(ClaimsPrincipal subject, ResourceValidationResult resourceResult, ValidatedRequest request)
        {
            Logger.LogDebug("Getting claims for access token for client: {clientId}", request.Client.ClientId);

            var outputClaims = new List<Claim>()
            {
                new Claim(JwtClaimTypes.ClientId, request.ClientId)
            };

            // log if client ID is overwritten
            if (!string.Equals(request.ClientId, request.Client.ClientId))
            {
                Logger.LogDebug("Client {clientId} is impersonating {impersonatedClientId}", request.Client.ClientId, request.ClientId);
            }

            // check for client claims
            if (request.ClientClaims != null && request.ClientClaims.Any())
            {
                if (subject == null || request.Client.AlwaysSendClientClaims)
                {
                    foreach (var claim in request.ClientClaims)
                    {
                        var claimType = claim.Type;

                        if (request.Client.ClientClaimsPrefix.IsPresent())
                        {
                            claimType = request.Client.ClientClaimsPrefix + claimType;
                        }

                        outputClaims.Add(new Claim(claimType, claim.Value, claim.ValueType));
                    }
                }
            }

            // add scopes (filter offline_access)
            // we use the ScopeValues collection rather than the Resources.Scopes because we support dynamic scope values 
            // from the request, so this issues those in the token.
            foreach (var scope in resourceResult.ScopeValues.Where(x => x != IdentityServerConstants.StandardScopes.OfflineAccess))
            {
                outputClaims.Add(new Claim(JwtClaimTypes.Scope, scope));
            }

            // a user is involved
            if (subject != null)
            {
                if (resourceResult.Resources.OfflineAccess)
                {
                    outputClaims.Add(new Claim(JwtClaimTypes.Scope, IdentityServerConstants.StandardScopes.OfflineAccess));
                }

                Logger.LogDebug("Getting claims for access token for subject: {subject}", subject.GetSubjectId());

                outputClaims.AddRange(GetStandardSubjectClaims(subject));
                outputClaims.AddRange(GetOptionalClaims(subject));

                // fetch all resource claims that need to go into the access token
                var additionalClaimTypes = new List<string>();
                foreach (var api in resourceResult.Resources.ApiResources)
                {
                    // add claims configured on api resource
                    if (api.UserClaims != null)
                    {
                        foreach (var claim in api.UserClaims)
                        {
                            additionalClaimTypes.Add(claim);
                        }
                    }
                }

                foreach(var scope in resourceResult.Resources.ApiScopes)
                {
                    // add claims configured on scopes
                    if (scope.UserClaims != null)
                    {
                        foreach (var claim in scope.UserClaims)
                        {
                            additionalClaimTypes.Add(claim);
                        }
                    }
                }

                // filter so we don't ask for claim types that we will eventually filter out
                additionalClaimTypes = FilterRequestedClaimTypes(additionalClaimTypes).ToList();

                var context = new ProfileDataRequestContext(
                    subject,
                    request.Client,
                    IdentityServerConstants.ProfileDataCallers.ClaimsProviderAccessToken,
                    additionalClaimTypes.Distinct())
                {
                    RequestedResources = resourceResult,
                    ValidatedRequest = request
                };

                await Profile.GetProfileDataAsync(context);

                var claims = FilterProtocolClaims(context.IssuedClaims);
                if (claims != null)
                {
                    outputClaims.AddRange(claims);
                }
            }

            return outputClaims;
        }

        /// <summary>
        /// Gets the standard subject claims.
        /// </summary>
        /// <param name="subject">The subject.</param>
        /// <returns>A list of standard claims</returns>
        protected virtual IEnumerable<Claim> GetStandardSubjectClaims(ClaimsPrincipal subject)
        {
            var claims = new List<Claim>
            {
                new Claim(JwtClaimTypes.Subject, subject.GetSubjectId()),
                new Claim(JwtClaimTypes.AuthenticationTime, subject.GetAuthenticationTimeEpoch().ToString(), ClaimValueTypes.Integer64),
                new Claim(JwtClaimTypes.IdentityProvider, subject.GetIdentityProvider())
            };

            claims.AddRange(subject.GetAuthenticationMethods());

            return claims;
        }

        /// <summary>
        /// Gets additional (and optional) claims from the cookie or incoming subject.
        /// </summary>
        /// <param name="subject">The subject.</param>
        /// <returns>Additional claims</returns>
        protected virtual IEnumerable<Claim> GetOptionalClaims(ClaimsPrincipal subject)
        {
            var claims = new List<Claim>();

            var acr = subject.FindFirst(JwtClaimTypes.AuthenticationContextClassReference);
            if (acr != null) claims.Add(acr);

            return claims;
        }

        /// <summary>
        /// Filters out protocol claims like amr, nonce etc..
        /// </summary>
        /// <param name="claims">The claims.</param>
        /// <returns></returns>
        protected virtual IEnumerable<Claim> FilterProtocolClaims(IEnumerable<Claim> claims)
        {
            var claimsToFilter = claims.Where(x => Constants.Filters.ClaimsServiceFilterClaimTypes.Contains(x.Type));
            if (claimsToFilter.Any())
            {
                var types = claimsToFilter.Select(x => x.Type);
                Logger.LogDebug("Claim types from profile service that were filtered: {claimTypes}", types);
            }
            return claims.Except(claimsToFilter);
        }

        /// <summary>
        /// Filters out protocol claims like amr, nonce etc..
        /// </summary>
        /// <param name="claimTypes">The claim types.</param>
        protected virtual IEnumerable<string> FilterRequestedClaimTypes(IEnumerable<string> claimTypes)
        {
            var claimTypesToFilter = claimTypes.Where(x => Constants.Filters.ClaimsServiceFilterClaimTypes.Contains(x));
            return claimTypes.Except(claimTypesToFilter);
        }
    }
}

  

10.AbpUserClaimsPrincipalFactory

using System;
using System.Linq;
using System.Security.Claims;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Identity;
using Microsoft.Extensions.Options;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Identity;
using Volo.Abp.Security.Claims;
using Volo.Abp.Uow;
using IdentityRole = Volo.Abp.Identity.IdentityRole;
using IdentityUser = Volo.Abp.Identity.IdentityUser;

namespace DRS.Identity
{
    [Dependency(ReplaceServices = true)]
    [ExposeServices(typeof(AbpUserClaimsPrincipalFactory))] // 替换旧的AbpUserClaimsPrincipalFactory
    public class MyUserClaimsPrincipalFactory : AbpUserClaimsPrincipalFactory, IScopedDependency
    {
        public MyUserClaimsPrincipalFactory(
            UserManager<IdentityUser> userManager,
            RoleManager<IdentityRole> roleManager,
            IOptions<IdentityOptions> options)
            : base(
                  userManager,
                  roleManager,
                  options)
        {
        }

        public override async Task<ClaimsPrincipal> CreateAsync(IdentityUser user)
        {
            var principal = await base.CreateAsync(user);
            var identityPrincipal = principal.Identities.First();
            /// add custom claim
             identityPrincipal.AddClaim(new Claim("fff", "ddddd"));

            return principal;
        }
    }
   
    
}

11. Permission 分为 Client  和 Role

GO
/****** Object:  StoredProcedure [dbo].[AddAPIScope]    Script Date: 2021/1/29 22:53:11 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO


ALTER PROCEDURE [dbo].[AddAPIScope] 
	@scope  nvarchar(500), 
	@client  nvarchar(500)='TEST_APP'
AS
BEGIN

	-- exec AddAPIScope 'DRS.TEST','TEST_APP'
	select @scope,@client

	merge into AbpPermissionGrants p
	using(select newid() as id,null as tenantid,@scope as name,'R' as providername,'admin' as providerkey) as t
	on(p.name=t.name and p.providername=t.providername and p.providerkey=t.providerkey)
	when not matched then 
	insert(id,tenantid,name,providername,providerkey) values(t.id,t.tenantid,t.name,t.providername,t.providerkey);
	

	merge into AbpPermissionGrants p
	using(select newid() as id,null as tenantid,@scope as name,'C' as providername,@client as providerkey) as t
	on(p.name=t.name and p.providername=t.providername and p.providerkey=t.providerkey)
	when not matched then 
	insert(id,tenantid,name,providername,providerkey) values(t.id,t.tenantid,t.name,t.providername,t.providerkey);


	merge into IdentityServerApiScopes p
	using(select id as apiresourceid,@scope as name,@scope+' API' as displayname,null as description,0 as required,0 as emphasize,1 as showindiscoverydocument
	 from [dbo].[IdentityServerApiResources] where name='TEST') as t
	on(p.apiresourceid =t.apiresourceid and p.name=t.name)
	when not matched then 
	insert(apiresourceid,name,displayname,description,required,emphasize,showindiscoverydocument) 
	values(t.apiresourceid,t.name,t.displayname,t.description,t.required,t.emphasize,t.showindiscoverydocument);


	merge into IdentityServerClientScopes p
	using(select id as clientid,@scope as scope from [dbo].[IdentityServerClients] where ClientId = @client) as t
	on(p.clientid =t.clientid and p.scope=t.scope)
	when not matched then 
	insert(clientid,scope) 
	values(t.clientid,t.scope);

	select * from [AbpPermissionGrants] where name = @scope
	select * from [IdentityServerApiScopes] where name = @scope
	select c.ClientId,cs.* from [IdentityServerClients] c,[IdentityServerClientScopes] cs where c.id=cs.ClientId and scope = @scope

END

  


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM