Browse Source

Merge pull request #1273 from colinin/lock-session-handler

fix(identity): Lock when handling user sessions
pull/1284/head
yx lin 1 year ago
committed by GitHub
parent
commit
21c62d50da
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 2
      aspnet-core/modules/identity/LINGYUN.Abp.Identity.Domain/LINGYUN/Abp/Identity/AbpIdentityDomainModule.cs
  2. 71
      aspnet-core/modules/identity/LINGYUN.Abp.Identity.Domain/LINGYUN/Abp/Identity/Session/IdentitySessionCacheItemSynchronizer.cs
  3. 28
      aspnet-core/modules/identity/LINGYUN.Abp.Identity.Domain/LINGYUN/Abp/Identity/Session/IdentitySessionCleanupBackgroundWorker.cs

2
aspnet-core/modules/identity/LINGYUN.Abp.Identity.Domain/LINGYUN/Abp/Identity/AbpIdentityDomainModule.cs

@ -5,6 +5,7 @@ using System.Threading.Tasks;
using Volo.Abp; using Volo.Abp;
using Volo.Abp.AutoMapper; using Volo.Abp.AutoMapper;
using Volo.Abp.BackgroundWorkers; using Volo.Abp.BackgroundWorkers;
using Volo.Abp.DistributedLocking;
using Volo.Abp.Domain.Entities.Events.Distributed; using Volo.Abp.Domain.Entities.Events.Distributed;
using Volo.Abp.Identity; using Volo.Abp.Identity;
using Volo.Abp.Modularity; using Volo.Abp.Modularity;
@ -14,6 +15,7 @@ namespace LINGYUN.Abp.Identity;
[DependsOn( [DependsOn(
typeof(AbpIdentityDomainSharedModule), typeof(AbpIdentityDomainSharedModule),
typeof(AbpDistributedLockingAbstractionsModule),
typeof(Volo.Abp.Identity.AbpIdentityDomainModule))] typeof(Volo.Abp.Identity.AbpIdentityDomainModule))]
public class AbpIdentityDomainModule : AbpModule public class AbpIdentityDomainModule : AbpModule
{ {

71
aspnet-core/modules/identity/LINGYUN.Abp.Identity.Domain/LINGYUN/Abp/Identity/Session/IdentitySessionCacheItemSynchronizer.cs

@ -4,6 +4,7 @@ using Microsoft.Extensions.Logging.Abstractions;
using System; using System;
using System.Threading.Tasks; using System.Threading.Tasks;
using Volo.Abp.DependencyInjection; using Volo.Abp.DependencyInjection;
using Volo.Abp.DistributedLocking;
using Volo.Abp.Domain.Entities.Events; using Volo.Abp.Domain.Entities.Events;
using Volo.Abp.Domain.Entities.Events.Distributed; using Volo.Abp.Domain.Entities.Events.Distributed;
using Volo.Abp.EventBus; using Volo.Abp.EventBus;
@ -22,15 +23,18 @@ public class IdentitySessionCacheItemSynchronizer :
{ {
public ILogger<IdentitySessionCacheItemSynchronizer> Logger { protected get; set; } public ILogger<IdentitySessionCacheItemSynchronizer> Logger { protected get; set; }
protected ISettingProvider SettingProvider { get; } protected ISettingProvider SettingProvider { get; }
protected IAbpDistributedLock DistributedLock { get; }
protected IIdentitySessionCache IdentitySessionCache { get; } protected IIdentitySessionCache IdentitySessionCache { get; }
protected IIdentitySessionStore IdentitySessionStore { get; } protected IIdentitySessionStore IdentitySessionStore { get; }
public IdentitySessionCacheItemSynchronizer( public IdentitySessionCacheItemSynchronizer(
ISettingProvider settingProvider, ISettingProvider settingProvider,
IAbpDistributedLock distributedLock,
IIdentitySessionCache identitySessionCache, IIdentitySessionCache identitySessionCache,
IIdentitySessionStore identitySessionStore) IIdentitySessionStore identitySessionStore)
{ {
SettingProvider = settingProvider; SettingProvider = settingProvider;
DistributedLock = distributedLock;
IdentitySessionCache = identitySessionCache; IdentitySessionCache = identitySessionCache;
IdentitySessionStore = identitySessionStore; IdentitySessionStore = identitySessionStore;
@ -45,34 +49,71 @@ public class IdentitySessionCacheItemSynchronizer :
[UnitOfWork] [UnitOfWork]
public async virtual Task HandleEventAsync(EntityCreatedEto<IdentitySessionEto> eventData) public async virtual Task HandleEventAsync(EntityCreatedEto<IdentitySessionEto> eventData)
{ {
await RefreshSessionCache(eventData.Entity); var lockKey = $"{nameof(IdentitySessionCacheItemSynchronizer)}_{nameof(EntityCreatedEto<IdentitySessionEto>)}";
await CheckConcurrentLoginStrategy(eventData.Entity); await using (var handle = await DistributedLock.TryAcquireAsync(lockKey))
{
Logger.LogInformation($"Lock is acquired for {lockKey}");
if (handle == null)
{
Logger.LogInformation($"Handle is null because of the locking for : {lockKey}");
return;
}
await RefreshSessionCache(eventData.Entity);
await CheckConcurrentLoginStrategy(eventData.Entity);
}
} }
[UnitOfWork]
public async virtual Task HandleEventAsync(IdentitySessionChangeAccessedEvent eventData) public async virtual Task HandleEventAsync(IdentitySessionChangeAccessedEvent eventData)
{ {
var idetitySession = await IdentitySessionStore.FindAsync(eventData.SessionId); var lockKey = $"{nameof(IdentitySessionCacheItemSynchronizer)}_{nameof(IdentitySessionChangeAccessedEvent)}";
if (idetitySession != null) await using (var handle = await DistributedLock.TryAcquireAsync(lockKey))
{ {
if (!eventData.IpAddresses.IsNullOrWhiteSpace()) Logger.LogInformation($"Lock is acquired for {lockKey}");
if (handle == null)
{ {
idetitySession.SetIpAddresses(eventData.IpAddresses.Split(",")); Logger.LogInformation($"Handle is null because of the locking for : {lockKey}");
return;
} }
idetitySession.UpdateLastAccessedTime(eventData.LastAccessed);
await IdentitySessionStore.UpdateAsync(idetitySession); var idetitySession = await IdentitySessionStore.FindAsync(eventData.SessionId);
} if (idetitySession != null)
else {
{ if (!eventData.IpAddresses.IsNullOrWhiteSpace())
// 数据库中不存在会话, 清理缓存, 后续请求会话失效 {
await IdentitySessionCache.RemoveAsync(eventData.SessionId); idetitySession.SetIpAddresses(eventData.IpAddresses.Split(","));
}
idetitySession.UpdateLastAccessedTime(eventData.LastAccessed);
await IdentitySessionStore.UpdateAsync(idetitySession);
}
else
{
// 数据库中不存在会话, 清理缓存, 后续请求会话失效
await IdentitySessionCache.RemoveAsync(eventData.SessionId);
}
} }
} }
public async virtual Task HandleEventAsync(EntityDeletedEventData<IdentityUser> eventData) public async virtual Task HandleEventAsync(EntityDeletedEventData<IdentityUser> eventData)
{ {
// 用户被删除, 移除所有会话 var lockKey = $"{nameof(IdentitySessionCacheItemSynchronizer)}_{nameof(EntityDeletedEventData<IdentityUser>)}";
await IdentitySessionStore.RevokeAllAsync(eventData.Entity.Id); await using (var handle = await DistributedLock.TryAcquireAsync(lockKey))
{
Logger.LogInformation($"Lock is acquired for {lockKey}");
if (handle == null)
{
Logger.LogInformation($"Handle is null because of the locking for : {lockKey}");
return;
}
// 用户被删除, 移除所有会话
await IdentitySessionStore.RevokeAllAsync(eventData.Entity.Id);
}
} }
protected async virtual Task RefreshSessionCache(IdentitySessionEto session) protected async virtual Task RefreshSessionCache(IdentitySessionEto session)

28
aspnet-core/modules/identity/LINGYUN.Abp.Identity.Domain/LINGYUN/Abp/Identity/Session/IdentitySessionCleanupBackgroundWorker.cs

@ -1,20 +1,25 @@
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options; using Microsoft.Extensions.Options;
using System.Threading.Tasks; using System.Threading.Tasks;
using Volo.Abp.BackgroundWorkers; using Volo.Abp.BackgroundWorkers;
using Volo.Abp.DistributedLocking;
using Volo.Abp.Threading; using Volo.Abp.Threading;
namespace LINGYUN.Abp.Identity.Session; namespace LINGYUN.Abp.Identity.Session;
public class IdentitySessionCleanupBackgroundWorker : AsyncPeriodicBackgroundWorkerBase public class IdentitySessionCleanupBackgroundWorker : AsyncPeriodicBackgroundWorkerBase
{ {
protected IAbpDistributedLock DistributedLock { get; }
protected IdentitySessionCleanupOptions Options { get; } protected IdentitySessionCleanupOptions Options { get; }
public IdentitySessionCleanupBackgroundWorker( public IdentitySessionCleanupBackgroundWorker(
AbpAsyncTimer timer, AbpAsyncTimer timer,
IServiceScopeFactory serviceScopeFactory, IServiceScopeFactory serviceScopeFactory,
IOptions<IdentitySessionCleanupOptions> options) IOptions<IdentitySessionCleanupOptions> options,
IAbpDistributedLock distributedLock)
: base(timer, serviceScopeFactory) : base(timer, serviceScopeFactory)
{ {
DistributedLock = distributedLock;
Options = options.Value; Options = options.Value;
timer.Period = Options.CleanupPeriod; timer.Period = Options.CleanupPeriod;
} }
@ -26,9 +31,22 @@ public class IdentitySessionCleanupBackgroundWorker : AsyncPeriodicBackgroundWor
return; return;
} }
await workerContext await using (var handle = await DistributedLock.TryAcquireAsync(nameof(IdentitySessionCleanupBackgroundWorker)))
.ServiceProvider {
.GetRequiredService<IdentitySessionCleanupService>() Logger.LogInformation($"Lock is acquired for {nameof(IdentitySessionCleanupBackgroundWorker)}");
.CleanAsync();
if (handle != null)
{
await workerContext
.ServiceProvider
.GetRequiredService<IdentitySessionCleanupService>()
.CleanAsync();
Logger.LogInformation($"Lock is released for {nameof(IdentitySessionCleanupBackgroundWorker)}");
return;
}
Logger.LogInformation($"Handle is null because of the locking for : {nameof(IdentitySessionCleanupBackgroundWorker)}");
}
} }
} }

Loading…
Cancel
Save