Update `AbpDynamicClaimsPrincipalContributorBase`.

pull/18064/head
maliming 2 years ago
parent a0415c26d7
commit 59a2227ffc

@ -1,5 +1,6 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
using System.Net.Http; using System.Net.Http;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.Extensions.Caching.Distributed; using Microsoft.Extensions.Caching.Distributed;
@ -59,7 +60,7 @@ public class RemoteDynamicClaimsPrincipalContributorCache : ITransientDependency
// Use independent cache for remote claims. // Use independent cache for remote claims.
return (await Cache.GetOrAddAsync($"{nameof(RemoteDynamicClaimsPrincipalContributorCache)}{AbpClaimCacheItem.CalculateCacheKey(userId, tenantId)}", async () => return (await Cache.GetOrAddAsync($"{nameof(RemoteDynamicClaimsPrincipalContributorCache)}{AbpClaimCacheItem.CalculateCacheKey(userId, tenantId)}", async () =>
{ {
var dynamicClaims = new List<AbpClaimCacheItem>(); var dynamicClaims = AbpClaimsPrincipalFactoryOptions.Value.DynamicClaims.Select(claimType => new AbpClaimCacheItem(claimType, null)).ToList();
Logger.LogDebug($"Get dynamic claims for user: {userId} from remote service."); Logger.LogDebug($"Get dynamic claims for user: {userId} from remote service.");
try try
{ {
@ -67,7 +68,11 @@ public class RemoteDynamicClaimsPrincipalContributorCache : ITransientDependency
var requestMessage = new HttpRequestMessage(HttpMethod.Get, AbpClaimsPrincipalFactoryOptions.Value.RemoteUrl); var requestMessage = new HttpRequestMessage(HttpMethod.Get, AbpClaimsPrincipalFactoryOptions.Value.RemoteUrl);
await HttpClientAuthenticator.Authenticate(new RemoteServiceHttpClientAuthenticateContext(client, requestMessage, new RemoteServiceConfiguration("/"), string.Empty)); await HttpClientAuthenticator.Authenticate(new RemoteServiceHttpClientAuthenticateContext(client, requestMessage, new RemoteServiceConfiguration("/"), string.Empty));
var response = await client.SendAsync(requestMessage); var response = await client.SendAsync(requestMessage);
dynamicClaims = JsonSerializer.Deserialize<List<AbpClaimCacheItem>>(await response.Content.ReadAsStringAsync()); var remoteClaims = JsonSerializer.Deserialize<List<AbpClaimCacheItem>>(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}"); Logger.LogDebug($"Successfully got {dynamicClaims.Count} remote claims for user: {userId}");
} }
catch (Exception e) catch (Exception e)

@ -7,9 +7,9 @@ public class AbpClaimCacheItem
{ {
public string Type { get; set; } 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; Type = type;
Value = value; Value = value;

@ -13,41 +13,41 @@ public abstract class AbpDynamicClaimsPrincipalContributorBase : IAbpDynamicClai
protected virtual async Task MapCommonClaimsAsync(ClaimsIdentity identity, List<AbpClaimCacheItem> dynamicClaims) protected virtual async Task MapCommonClaimsAsync(ClaimsIdentity identity, List<AbpClaimCacheItem> dynamicClaims)
{ {
await MapClaimsAsync(identity, dynamicClaims, identity.NameClaimType, "preferred_username"); await MapClaimAsync(identity, dynamicClaims, AbpClaimTypes.UserName, "preferred_username", "unique_name", ClaimTypes.Name);
await MapClaimsAsync(identity, dynamicClaims, identity.NameClaimType, ClaimTypes.Name); await MapClaimAsync(identity, dynamicClaims, AbpClaimTypes.Role, "role", "roles", ClaimTypes.Role);
await MapClaimsAsync(identity, dynamicClaims, identity.RoleClaimType, "role"); await MapClaimAsync(identity, dynamicClaims, AbpClaimTypes.Email, "email", ClaimTypes.Email);
await MapClaimsAsync(identity, dynamicClaims, identity.RoleClaimType, ClaimTypes.Role); await MapClaimAsync(identity, dynamicClaims, AbpClaimTypes.SurName, "family_name", ClaimTypes.Surname);
await MapClaimsAsync(identity, dynamicClaims, "email", ClaimTypes.Email); await MapClaimAsync(identity, dynamicClaims, AbpClaimTypes.Name, "given_name", ClaimTypes.GivenName);
await MapClaimsAsync(identity, dynamicClaims, "family_name", ClaimTypes.Surname);
await MapClaimsAsync(identity, dynamicClaims, "given_name", ClaimTypes.GivenName);
} }
protected virtual Task MapClaimsAsync(ClaimsIdentity identity, List<AbpClaimCacheItem> dynamicClaims, string sourceType, string targetType) protected virtual Task MapClaimAsync(ClaimsIdentity identity, List<AbpClaimCacheItem> 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(); var claim = claimGroup.First();
if (!claims.IsNullOrEmpty()) if (claimGroup.Count() > 1)
{ {
identity.RemoveAll(sourceType); dynamicClaims.RemoveAll(c => c.Type == claim.Type && identity.Claims.All(x => x.Type != claim.Type));
identity.AddClaims(claims.Select(c => new Claim(sourceType, c.Value))); identity.RemoveAll(abpClaimType);
dynamicClaims.RemoveAll(c => c.Type == targetType); identity.AddClaims(claimGroup.Where(c => c.Value != null).Select(c => new Claim(abpClaimType, c.Value!)));
} }
} else
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())
{ {
identity.RemoveAll(targetType); dynamicClaims.RemoveAll(c => c.Type == claim.Type && identity.Claims.All(x => x.Type != claim.Type));
identity.AddClaims(claims.Select(c => new Claim(targetType, c.Value))); if (claim.Value != null)
dynamicClaims.RemoveAll(c => c.Type == sourceType); {
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<AbpClaimCacheItem> dynamicClaims) protected virtual Task AddDynamicClaims(ClaimsIdentity identity, List<AbpClaimCacheItem> 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.RemoveAll(claimGroup.First().Type);
identity.AddClaims(claims.Select(c => new Claim(claims.First().Type, c.Value))); identity.AddClaims(claimGroup.Where(c => c.Value != null).Select(c => new Claim(claimGroup.First().Type, c.Value!)));
} }
else 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);
}
} }
} }

@ -5,4 +5,10 @@ public class DynamicClaimDto
public string Type { get; set; } public string Type { get; set; }
public string Value { get; set; } public string Value { get; set; }
public DynamicClaimDto(string type, string value)
{
Type = type;
Value = value;
}
} }

@ -29,14 +29,20 @@ public class DynamicClaimsAppService : IdentityAppServiceBase, IDynamicClaimsApp
{ {
var principal = await AbpClaimsPrincipalFactory.CreateAsync(PrincipalAccessor.Principal); var principal = await AbpClaimsPrincipalFactory.CreateAsync(PrincipalAccessor.Principal);
var dynamicClaims = principal.Claims var dynamicClaims = new List<DynamicClaimDto>();
.Where(c => AbpClaimsPrincipalFactoryOptions.Value.DynamicClaims.Contains(c.Type)) foreach (var claimType in AbpClaimsPrincipalFactoryOptions.Value.DynamicClaims)
.Select(c => new DynamicClaimDto {
var claims = principal.Claims.Where(x => x.Type == claimType).ToList();
if (claims.Any())
{ {
Type = c.Type, dynamicClaims.AddRange(claims.Select(claim => new DynamicClaimDto(claimType, claim.Value)));
Value = c.Value }
}); else
{
dynamicClaims.Add(new DynamicClaimDto(claimType, null));
}
}
return dynamicClaims.ToList(); return dynamicClaims;
} }
} }

@ -55,9 +55,22 @@ public class IdentityDynamicClaimsPrincipalContributorCache : ITransientDependen
var user = await UserManager.GetByIdAsync(userId); var user = await UserManager.GetByIdAsync(userId);
var principal = await UserClaimsPrincipalFactory.CreateAsync(user); var principal = await UserClaimsPrincipalFactory.CreateAsync(user);
return principal.Identities.FirstOrDefault()?.Claims
.Where(c => AbpClaimsPrincipalFactoryOptions.Value.DynamicClaims.Contains(c.Type)) var dynamicClaims = new List<AbpClaimCacheItem>();
.Select(c => new AbpClaimCacheItem(c.Type, c.Value)).ToList(); 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 }, () => new DistributedCacheEntryOptions
{ {

Loading…
Cancel
Save