diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.Client.Common/Volo/Abp/AspNetCore/Mvc/Client/RemoteDynamicClaimsPrincipalContributorCache.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.Client.Common/Volo/Abp/AspNetCore/Mvc/Client/RemoteDynamicClaimsPrincipalContributorCache.cs index 33a1dfd5f6..400d42349c 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.Client.Common/Volo/Abp/AspNetCore/Mvc/Client/RemoteDynamicClaimsPrincipalContributorCache.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.Client.Common/Volo/Abp/AspNetCore/Mvc/Client/RemoteDynamicClaimsPrincipalContributorCache.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Linq; using System.Net.Http; using System.Threading.Tasks; using Microsoft.Extensions.Caching.Distributed; @@ -59,7 +60,7 @@ public class RemoteDynamicClaimsPrincipalContributorCache : ITransientDependency // Use independent cache for remote claims. return (await Cache.GetOrAddAsync($"{nameof(RemoteDynamicClaimsPrincipalContributorCache)}{AbpClaimCacheItem.CalculateCacheKey(userId, tenantId)}", async () => { - var dynamicClaims = new List(); + var dynamicClaims = AbpClaimsPrincipalFactoryOptions.Value.DynamicClaims.Select(claimType => new AbpClaimCacheItem(claimType, null)).ToList(); Logger.LogDebug($"Get dynamic claims for user: {userId} from remote service."); try { @@ -67,7 +68,11 @@ public class RemoteDynamicClaimsPrincipalContributorCache : ITransientDependency var requestMessage = new HttpRequestMessage(HttpMethod.Get, AbpClaimsPrincipalFactoryOptions.Value.RemoteUrl); await HttpClientAuthenticator.Authenticate(new RemoteServiceHttpClientAuthenticateContext(client, requestMessage, new RemoteServiceConfiguration("/"), string.Empty)); var response = await client.SendAsync(requestMessage); - dynamicClaims = JsonSerializer.Deserialize>(await response.Content.ReadAsStringAsync()); + var remoteClaims = JsonSerializer.Deserialize>(await response.Content.ReadAsStringAsync()); + foreach (var claim in dynamicClaims) + { + claim.Value = remoteClaims.FirstOrDefault(c => c.Type == claim.Type)?.Value; + } Logger.LogDebug($"Successfully got {dynamicClaims.Count} remote claims for user: {userId}"); } catch (Exception e) diff --git a/framework/src/Volo.Abp.Security/Volo/Abp/Security/Claims/AbpClaimCacheIteam.cs b/framework/src/Volo.Abp.Security/Volo/Abp/Security/Claims/AbpClaimCacheIteam.cs index 02f15e2478..94241284fe 100644 --- a/framework/src/Volo.Abp.Security/Volo/Abp/Security/Claims/AbpClaimCacheIteam.cs +++ b/framework/src/Volo.Abp.Security/Volo/Abp/Security/Claims/AbpClaimCacheIteam.cs @@ -7,9 +7,9 @@ public class AbpClaimCacheItem { public string Type { get; set; } - public string Value { get; set; } + public string? Value { get; set; } - public AbpClaimCacheItem(string type, string value) + public AbpClaimCacheItem(string type, string? value) { Type = type; Value = value; diff --git a/framework/src/Volo.Abp.Security/Volo/Abp/Security/Claims/AbpDynamicClaimsPrincipalContributorBase.cs b/framework/src/Volo.Abp.Security/Volo/Abp/Security/Claims/AbpDynamicClaimsPrincipalContributorBase.cs index 55f2dc96a6..71ec0ae7c2 100644 --- a/framework/src/Volo.Abp.Security/Volo/Abp/Security/Claims/AbpDynamicClaimsPrincipalContributorBase.cs +++ b/framework/src/Volo.Abp.Security/Volo/Abp/Security/Claims/AbpDynamicClaimsPrincipalContributorBase.cs @@ -13,41 +13,41 @@ public abstract class AbpDynamicClaimsPrincipalContributorBase : IAbpDynamicClai protected virtual async Task MapCommonClaimsAsync(ClaimsIdentity identity, List dynamicClaims) { - await MapClaimsAsync(identity, dynamicClaims, identity.NameClaimType, "preferred_username"); - await MapClaimsAsync(identity, dynamicClaims, identity.NameClaimType, ClaimTypes.Name); - await MapClaimsAsync(identity, dynamicClaims, identity.RoleClaimType, "role"); - await MapClaimsAsync(identity, dynamicClaims, identity.RoleClaimType, ClaimTypes.Role); - await MapClaimsAsync(identity, dynamicClaims, "email", ClaimTypes.Email); - await MapClaimsAsync(identity, dynamicClaims, "family_name", ClaimTypes.Surname); - await MapClaimsAsync(identity, dynamicClaims, "given_name", ClaimTypes.GivenName); + await MapClaimAsync(identity, dynamicClaims, AbpClaimTypes.UserName, "preferred_username", "unique_name", ClaimTypes.Name); + await MapClaimAsync(identity, dynamicClaims, AbpClaimTypes.Role, "role", "roles", ClaimTypes.Role); + await MapClaimAsync(identity, dynamicClaims, AbpClaimTypes.Email, "email", ClaimTypes.Email); + await MapClaimAsync(identity, dynamicClaims, AbpClaimTypes.SurName, "family_name", ClaimTypes.Surname); + await MapClaimAsync(identity, dynamicClaims, AbpClaimTypes.Name, "given_name", ClaimTypes.GivenName); } - protected virtual Task MapClaimsAsync(ClaimsIdentity identity, List dynamicClaims, string sourceType, string targetType) + protected virtual Task MapClaimAsync(ClaimsIdentity identity, List dynamicClaims, string abpClaimType, params string[] dynamicClaimTypes) { - if (sourceType == targetType) + var claims = dynamicClaims.Where(c => dynamicClaimTypes.Contains(c.Type)).ToList(); + if (claims.IsNullOrEmpty()) { - return Task.CompletedTask;; + return Task.CompletedTask; } - if (identity.Claims.Any(c => c.Type == sourceType) && dynamicClaims.All(c => c.Type != sourceType)) + foreach (var claimGroup in claims.GroupBy(x => x.Type)) { - var claims = dynamicClaims.Where(c => c.Type == targetType).ToList(); - if (!claims.IsNullOrEmpty()) + var claim = claimGroup.First(); + if (claimGroup.Count() > 1) { - identity.RemoveAll(sourceType); - identity.AddClaims(claims.Select(c => new Claim(sourceType, c.Value))); - dynamicClaims.RemoveAll(c => c.Type == targetType); + dynamicClaims.RemoveAll(c => c.Type == claim.Type && identity.Claims.All(x => x.Type != claim.Type)); + identity.RemoveAll(abpClaimType); + identity.AddClaims(claimGroup.Where(c => c.Value != null).Select(c => new Claim(abpClaimType, c.Value!))); } - } - - if (identity.Claims.Any(c => c.Type == targetType) && dynamicClaims.All(c => c.Type != targetType)) - { - var claims = dynamicClaims.Where(c => c.Type == sourceType).ToList(); - if (!claims.IsNullOrEmpty()) + else { - identity.RemoveAll(targetType); - identity.AddClaims(claims.Select(c => new Claim(targetType, c.Value))); - dynamicClaims.RemoveAll(c => c.Type == sourceType); + dynamicClaims.RemoveAll(c => c.Type == claim.Type && identity.Claims.All(x => x.Type != claim.Type)); + if (claim.Value != null) + { + identity.AddOrReplace(new Claim(abpClaimType, claim.Value)); + } + else + { + identity.RemoveAll(abpClaimType); + } } } @@ -56,16 +56,24 @@ public abstract class AbpDynamicClaimsPrincipalContributorBase : IAbpDynamicClai protected virtual Task AddDynamicClaims(ClaimsIdentity identity, List dynamicClaims) { - foreach (var claims in dynamicClaims.GroupBy(x => x.Type)) + foreach (var claimGroup in dynamicClaims.GroupBy(x => x.Type)) { - if (claims.Count() > 1) + if (claimGroup.Count() > 1) { - identity.RemoveAll(claims.First().Type); - identity.AddClaims(claims.Select(c => new Claim(claims.First().Type, c.Value))); + identity.RemoveAll(claimGroup.First().Type); + identity.AddClaims(claimGroup.Where(c => c.Value != null).Select(c => new Claim(claimGroup.First().Type, c.Value!))); } else { - identity.AddOrReplace(new Claim(claims.First().Type, claims.First().Value)); + var claim = claimGroup.First(); + if (claim.Value != null) + { + identity.AddOrReplace(new Claim(claimGroup.First().Type, claim.Value)); + } + else + { + identity.RemoveAll(claim.Type); + } } } diff --git a/modules/account/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/DynamicClaimDto.cs b/modules/account/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/DynamicClaimDto.cs index 896263e08f..ad5ac82678 100644 --- a/modules/account/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/DynamicClaimDto.cs +++ b/modules/account/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/DynamicClaimDto.cs @@ -5,4 +5,10 @@ public class DynamicClaimDto public string Type { get; set; } public string Value { get; set; } + + public DynamicClaimDto(string type, string value) + { + Type = type; + Value = value; + } } diff --git a/modules/account/src/Volo.Abp.Account.Application/Volo/Abp/Account/DynamicClaimsAppService.cs b/modules/account/src/Volo.Abp.Account.Application/Volo/Abp/Account/DynamicClaimsAppService.cs index ebe9e06cb7..d32d265d4a 100644 --- a/modules/account/src/Volo.Abp.Account.Application/Volo/Abp/Account/DynamicClaimsAppService.cs +++ b/modules/account/src/Volo.Abp.Account.Application/Volo/Abp/Account/DynamicClaimsAppService.cs @@ -29,14 +29,20 @@ public class DynamicClaimsAppService : IdentityAppServiceBase, IDynamicClaimsApp { var principal = await AbpClaimsPrincipalFactory.CreateAsync(PrincipalAccessor.Principal); - var dynamicClaims = principal.Claims - .Where(c => AbpClaimsPrincipalFactoryOptions.Value.DynamicClaims.Contains(c.Type)) - .Select(c => new DynamicClaimDto + var dynamicClaims = new List(); + foreach (var claimType in AbpClaimsPrincipalFactoryOptions.Value.DynamicClaims) + { + var claims = principal.Claims.Where(x => x.Type == claimType).ToList(); + if (claims.Any()) { - Type = c.Type, - Value = c.Value - }); + dynamicClaims.AddRange(claims.Select(claim => new DynamicClaimDto(claimType, claim.Value))); + } + else + { + dynamicClaims.Add(new DynamicClaimDto(claimType, null)); + } + } - return dynamicClaims.ToList(); + return dynamicClaims; } } diff --git a/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentityDynamicClaimsPrincipalContributorCache.cs b/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentityDynamicClaimsPrincipalContributorCache.cs index 51b16aa88f..f3014adfce 100644 --- a/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentityDynamicClaimsPrincipalContributorCache.cs +++ b/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentityDynamicClaimsPrincipalContributorCache.cs @@ -55,9 +55,22 @@ public class IdentityDynamicClaimsPrincipalContributorCache : ITransientDependen var user = await UserManager.GetByIdAsync(userId); var principal = await UserClaimsPrincipalFactory.CreateAsync(user); - return principal.Identities.FirstOrDefault()?.Claims - .Where(c => AbpClaimsPrincipalFactoryOptions.Value.DynamicClaims.Contains(c.Type)) - .Select(c => new AbpClaimCacheItem(c.Type, c.Value)).ToList(); + + var dynamicClaims = new List(); + foreach (var claimType in AbpClaimsPrincipalFactoryOptions.Value.DynamicClaims) + { + var claims = principal.Claims.Where(x => x.Type == claimType).ToList(); + if (claims.Any()) + { + dynamicClaims.AddRange(claims.Select(claim => new AbpClaimCacheItem(claimType, claim.Value))); + } + else + { + dynamicClaims.Add(new AbpClaimCacheItem(claimType, null)); + } + } + + return dynamicClaims; } }, () => new DistributedCacheEntryOptions {