Add `IdentityDynamicClaimsPrincipalContributor`.

pull/18064/head
maliming 1 year ago
parent 7fde5e3dd1
commit 44ef56c2d8
No known key found for this signature in database
GPG Key ID: A646B9CB645ECEA4

@ -0,0 +1,17 @@
using System;
namespace Volo.Abp.Security.Claims;
[Serializable]
public class AbpClaimCacheItem
{
public string Type { get; set; }
public string Value { get; set; }
public AbpClaimCacheItem(string type, string value)
{
Type = type;
Value = value;
}
}

@ -1,6 +1,7 @@
using System;
using System.Security.Claims;
using JetBrains.Annotations;
using Microsoft.Extensions.DependencyInjection;
namespace Volo.Abp.Security.Claims;
@ -19,4 +20,11 @@ public class AbpClaimsPrincipalContributorContext
ClaimsPrincipal = claimsIdentity;
ServiceProvider = serviceProvider;
}
public virtual T GetRequiredService<T>()
where T : notnull
{
Check.NotNull(ServiceProvider, nameof(ServiceProvider));
return ServiceProvider.GetRequiredService<T>();
}
}

@ -62,6 +62,11 @@ public class AbpIdentityDomainModule : AbpModule
});
context.Services.AddAbpDynamicOptions<IdentityOptions, AbpIdentityOptionsManager>();
Configure<AbpClaimsPrincipalFactoryOptions>(options =>
{
options.DynamicContributors.Add<IdentityDynamicClaimsPrincipalContributor>();
});
}
public override void PostConfigureServices(ServiceConfigurationContext context)

@ -33,7 +33,7 @@ public class AbpUserClaimsPrincipalFactory : UserClaimsPrincipalFactory<Identity
}
[UnitOfWork]
public override async Task<ClaimsPrincipal> CreateAsync(IdentityUser user)
public async override Task<ClaimsPrincipal> CreateAsync(IdentityUser user)
{
var principal = await base.CreateAsync(user);
var identity = principal.Identities.First();

@ -0,0 +1,28 @@
using System.Linq;
using System.Security.Claims;
using System.Security.Principal;
using System.Threading.Tasks;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Security.Claims;
namespace Volo.Abp.Identity;
public class IdentityDynamicClaimsPrincipalContributor : IAbpClaimsPrincipalContributor, ITransientDependency
{
public virtual async Task ContributeAsync(AbpClaimsPrincipalContributorContext context)
{
var identity = context.ClaimsPrincipal.Identities.FirstOrDefault();
var userId = identity?.FindUserId();
if (userId == null)
{
return;
}
var cache = context.GetRequiredService<IdentityDynamicClaimsPrincipalContributorCache>();
var dynamicClaims = await cache.GetAsync(userId.Value, identity.FindTenantId());
foreach (var claim in dynamicClaims)
{
identity.AddOrReplace(new Claim(claim.Type, claim.Value));
}
}
}

@ -0,0 +1,60 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Claims;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Identity;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Volo.Abp.Caching;
using Volo.Abp.DependencyInjection;
using Volo.Abp.MultiTenancy;
using Volo.Abp.Security.Claims;
namespace Volo.Abp.Identity;
public class IdentityDynamicClaimsPrincipalContributorCache : ITransientDependency
{
protected IServiceProvider ServiceProvider { get; }
public IdentityDynamicClaimsPrincipalContributorCache(IServiceProvider serviceProvider)
{
this.ServiceProvider = serviceProvider;
}
public virtual async Task<List<AbpClaimCacheItem>> GetAsync(Guid userId, Guid? tenantId = null)
{
var logger = ServiceProvider.GetRequiredService<ILogger<IdentityDynamicClaimsPrincipalContributorCache>>();
logger.LogDebug($"Get dynamic claims cache for user: {userId}");
var cache = ServiceProvider.GetRequiredService<IDistributedCache<List<AbpClaimCacheItem>>>();
return await cache.GetOrAddAsync($"{nameof(IdentityDynamicClaimsPrincipalContributorCache)}_{tenantId}_{userId}", async () =>
{
using (ServiceProvider.GetRequiredService<ICurrentTenant>().Change(tenantId))
{
logger.LogDebug($"Filling dynamic claims cache for user: {userId}");
var userManager = ServiceProvider.GetRequiredService<IdentityUserManager>();
var user = await userManager.FindByIdAsync(userId.ToString());
if (user == null)
{
logger.LogWarning($"User not found: {userId}");
return new List<AbpClaimCacheItem>();
}
var factory = ServiceProvider.GetRequiredService<IUserClaimsPrincipalFactory<IdentityUser>>();
var principal = await factory.CreateAsync(user);
var options = ServiceProvider.GetRequiredService<IOptions<AbpClaimsPrincipalFactoryOptions>>().Value;
return principal.Identities.FirstOrDefault()?.Claims.Where(c => options.DynamicClaims.Contains(c.Type)).Select(c => new AbpClaimCacheItem(c.Type, c.Value)).ToList();
}
});
}
public virtual async Task ClearAsync(Guid userId, Guid? tenantId = null)
{
var cache = ServiceProvider.GetRequiredService<IDistributedCache<List<AbpClaimCacheItem>>>();
var logger = ServiceProvider.GetRequiredService<ILogger<IdentityDynamicClaimsPrincipalContributorCache>>();
logger.LogDebug($"Clearing dynamic claims cache for user: {userId}");
await cache.RemoveAsync($"{nameof(IdentityDynamicClaimsPrincipalContributorCache)}_{tenantId}_{userId}");
}
}

@ -0,0 +1,30 @@
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Domain.Entities.Events;
using Volo.Abp.EventBus;
using Volo.Abp.Uow;
namespace Volo.Abp.Identity;
public class UserEntityUpdatedEventHandler : ILocalEventHandler<EntityUpdatedEventData<IdentityUser>>, ITransientDependency
{
public ILogger<UserEntityUpdatedEventHandler> Logger { get; set; }
private readonly IdentityDynamicClaimsPrincipalContributorCache _cache;
public UserEntityUpdatedEventHandler(IdentityDynamicClaimsPrincipalContributorCache cache)
{
_cache = cache;
Logger = NullLogger<UserEntityUpdatedEventHandler>.Instance;
}
[UnitOfWork]
public virtual async Task HandleEventAsync(EntityUpdatedEventData<IdentityUser> eventData)
{
var userId = eventData.Entity.Id;
Logger.LogDebug($"Clearing dynamic claims cache for user: {userId}");
await _cache.ClearAsync(userId, eventData.Entity.TenantId);
}
}
Loading…
Cancel
Save