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

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

“Scope parameter exceeds max allowed length”

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

1
2
3
4
private static void ConfigureExistingProperties()
{
  ClientScopeConsts.ScopeMaxLength = 1000;
} 

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

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

1
2
3
4
5
6
7
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

1
2
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

1
2
3
4
5
6
7
8
//在正式环境中,这可能会报错
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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
// 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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
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

  

posted on   白马酒凉  阅读(1948)  评论(0编辑  收藏  举报

编辑推荐:
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
阅读排行:
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· Docker 太简单,K8s 太复杂?w7panel 让容器管理更轻松!
< 2025年3月 >
23 24 25 26 27 28 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31 1 2 3 4 5

导航

统计

点击右上角即可分享
微信分享提示