Browse Source

feat(identity): calculate session expiration time from identity claim principal

pull/1024/head
colin 1 year ago
parent
commit
36bc7676fe
  1. 18
      aspnet-core/modules/identity/LINGYUN.Abp.Identity.Domain/LINGYUN/Abp/Identity/Session/IdentitySessionManager.cs
  2. 36
      aspnet-core/modules/identity/LINGYUN.Abp.Identity.Domain/System/Security/Principal/AbpClaimsIdentityExpiraInExtensions.cs
  3. 6
      aspnet-core/modules/identity/LINGYUN.Abp.Identity.Session.AspNetCore/LINGYUN/Abp/Identity/Session/AspNetCore/AbpIdentitySessionAspNetCoreModule.cs
  4. 4
      aspnet-core/modules/identity/LINGYUN.Abp.Identity.Session.AspNetCore/LINGYUN/Abp/Identity/Session/AspNetCore/IP2RegionLocationInfoProvider.cs
  5. 15
      aspnet-core/modules/identity/LINGYUN.Abp.Identity.Session/LINGYUN/Abp/Identity/Session/DefaultIdentitySessionCache.cs
  6. 43
      aspnet-core/modules/identity/LINGYUN.Abp.Identity.Session/LINGYUN/Abp/Identity/Session/IdentitySessionCacheItem.cs

18
aspnet-core/modules/identity/LINGYUN.Abp.Identity.Domain/LINGYUN/Abp/Identity/Session/IdentitySessionManager.cs

@ -76,7 +76,19 @@ public class IdentitySessionManager : DomainService, IIdentitySessionManager
await IdentityDynamicClaimsPrincipalContributorCache.ClearAsync(userId.Value, tenantId); await IdentityDynamicClaimsPrincipalContributorCache.ClearAsync(userId.Value, tenantId);
await IdentitySessionCache.RefreshAsync(sessionId, // 2024-10-10 从令牌中取颁布时间与过期时间计算时间戳,作为默认缓存过期时间
double? expiraIn = null;
var expirainTime = claimsPrincipal.FindExpirainTime();
var issuedTime = claimsPrincipal.FindIssuedTime();
if (expirainTime.HasValue && issuedTime.HasValue)
{
expiraIn = DateTimeOffset.FromUnixTimeMilliseconds(expirainTime.Value)
.Subtract(DateTimeOffset.FromUnixTimeMilliseconds(issuedTime.Value))
.TotalMicroseconds;
}
await IdentitySessionCache.RefreshAsync(
sessionId,
new IdentitySessionCacheItem( new IdentitySessionCacheItem(
device, device,
deviceDesc, deviceDesc,
@ -86,7 +98,9 @@ public class IdentitySessionManager : DomainService, IIdentitySessionManager
clientIpAddress, clientIpAddress,
Clock.Now, Clock.Now,
Clock.Now, Clock.Now,
deviceInfo.IpRegion)); deviceInfo.IpRegion,
expiraIn),
cancellationToken);
} }
} }
} }

36
aspnet-core/modules/identity/LINGYUN.Abp.Identity.Domain/System/Security/Principal/AbpClaimsIdentityExpiraInExtensions.cs

@ -0,0 +1,36 @@
using JetBrains.Annotations;
using System.Linq;
using System.Security.Claims;
using Volo.Abp;
namespace System.Security.Principal;
public static class AbpClaimsIdentityExpiraInExtensions
{
public static long? FindExpirainTime([NotNull] this ClaimsPrincipal principal)
{
return principal.FindLongClaimValue("exp");
}
public static long? FindIssuedTime([NotNull] this ClaimsPrincipal principal)
{
return principal.FindLongClaimValue("iat");
}
public static long? FindLongClaimValue([NotNull] this ClaimsPrincipal principal, string claimType)
{
Check.NotNull(principal, nameof(principal));
var longValueOrNull = principal.Claims?.FirstOrDefault(c => c.Type == claimType);
if (longValueOrNull == null || longValueOrNull.Value.IsNullOrWhiteSpace())
{
return null;
}
if (long.TryParse(longValueOrNull.Value, out var longValue))
{
return longValue;
}
return null;
}
}

6
aspnet-core/modules/identity/LINGYUN.Abp.Identity.Session.AspNetCore/LINGYUN/Abp/Identity/Session/AspNetCore/AbpIdentitySessionAspNetCoreModule.cs

@ -1,4 +1,6 @@
using LINGYUN.Abp.IP2Region; using LINGYUN.Abp.IP2Region;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
using Volo.Abp.AspNetCore; using Volo.Abp.AspNetCore;
using Volo.Abp.Modularity; using Volo.Abp.Modularity;
@ -9,4 +11,8 @@ namespace LINGYUN.Abp.Identity.Session.AspNetCore;
[DependsOn(typeof(AbpIdentitySessionModule))] [DependsOn(typeof(AbpIdentitySessionModule))]
public class AbpIdentitySessionAspNetCoreModule : AbpModule public class AbpIdentitySessionAspNetCoreModule : AbpModule
{ {
public override void ConfigureServices(ServiceConfigurationContext context)
{
context.Services.Replace(ServiceDescriptor.Singleton<IIpLocationInfoProvider, IP2RegionLocationInfoProvider>());
}
} }

4
aspnet-core/modules/identity/LINGYUN.Abp.Identity.Session.AspNetCore/LINGYUN/Abp/Identity/Session/AspNetCore/IP2RegionLocationInfoProvider.cs

@ -1,10 +1,10 @@
using IP2Region.Net.Abstractions; using IP2Region.Net.Abstractions;
using System; using System;
using System.Threading.Tasks; using System.Threading.Tasks;
using Volo.Abp.DependencyInjection;
namespace LINGYUN.Abp.Identity.Session.AspNetCore; namespace LINGYUN.Abp.Identity.Session.AspNetCore;
public class IP2RegionLocationInfoProvider : IIpLocationInfoProvider, ISingletonDependency
public class IP2RegionLocationInfoProvider : IIpLocationInfoProvider
{ {
protected static readonly LocationInfo _nullCache = null; protected static readonly LocationInfo _nullCache = null;

15
aspnet-core/modules/identity/LINGYUN.Abp.Identity.Session/LINGYUN/Abp/Identity/Session/DefaultIdentitySessionCache.cs

@ -1,5 +1,7 @@
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Caching.Distributed;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions; using Microsoft.Extensions.Logging.Abstractions;
using System;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using Volo.Abp.Caching; using Volo.Abp.Caching;
@ -9,6 +11,7 @@ namespace LINGYUN.Abp.Identity.Session;
public class DefaultIdentitySessionCache : IIdentitySessionCache, ITransientDependency public class DefaultIdentitySessionCache : IIdentitySessionCache, ITransientDependency
{ {
public ILogger<DefaultIdentitySessionCache> Logger { protected get; set; } public ILogger<DefaultIdentitySessionCache> Logger { protected get; set; }
protected IDistributedCache<IdentitySessionCacheItem> Cache { get; } protected IDistributedCache<IdentitySessionCacheItem> Cache { get; }
public DefaultIdentitySessionCache(IDistributedCache<IdentitySessionCacheItem> cache) public DefaultIdentitySessionCache(IDistributedCache<IdentitySessionCacheItem> cache)
@ -31,8 +34,16 @@ public class DefaultIdentitySessionCache : IIdentitySessionCache, ITransientDepe
Logger.LogDebug($"Refresh user session cache for: {sessionId}"); Logger.LogDebug($"Refresh user session cache for: {sessionId}");
var cacheKey = IdentitySessionCacheItem.CalculateCacheKey(sessionId); var cacheKey = IdentitySessionCacheItem.CalculateCacheKey(sessionId);
DistributedCacheEntryOptions cacheOptions = null;
if (cacheItem.ExpiraIn.HasValue)
{
cacheOptions = new DistributedCacheEntryOptions
{
AbsoluteExpirationRelativeToNow = TimeSpan.FromMilliseconds(cacheItem.ExpiraIn.Value),
};
}
await Cache.SetAsync(cacheKey, cacheItem, token: cancellationToken); await Cache.SetAsync(cacheKey, cacheItem, options: cacheOptions, token: cancellationToken);
} }
public async virtual Task RemoveAsync(string sessionId, CancellationToken cancellationToken = default) public async virtual Task RemoveAsync(string sessionId, CancellationToken cancellationToken = default)

43
aspnet-core/modules/identity/LINGYUN.Abp.Identity.Session/LINGYUN/Abp/Identity/Session/IdentitySessionCacheItem.cs

@ -6,23 +6,46 @@ namespace LINGYUN.Abp.Identity.Session;
public class IdentitySessionCacheItem public class IdentitySessionCacheItem
{ {
private const string CacheKeyFormat = "s:{0}"; private const string CacheKeyFormat = "s:{0}";
/// <summary>
/// 登录设备
/// </summary>
public string Device { get; set; } public string Device { get; set; }
/// <summary>
/// 设备描述
/// </summary>
public string DeviceInfo { get; set; } public string DeviceInfo { get; set; }
/// <summary>
/// 用户Id
/// </summary>
public Guid UserId { get; set; } public Guid UserId { get; set; }
/// <summary>
/// 会话Id
/// </summary>
public string SessionId { get; set; } public string SessionId { get; set; }
/// <summary>
/// 客户端Id
/// </summary>
public string ClientId { get; set; } public string ClientId { get; set; }
/// <summary>
/// IP地址
/// </summary>
public string IpAddresses { get; set; } public string IpAddresses { get; set; }
/// <summary>
/// IP属地
/// </summary>
public string IpRegion { get; set; } public string IpRegion { get; set; }
/// <summary>
/// 登录时间
/// </summary>
public DateTime SignedIn { get; set; } public DateTime SignedIn { get; set; }
/// <summary>
/// 上次访问时间
/// </summary>
public DateTime? LastAccessed { get; set; } public DateTime? LastAccessed { get; set; }
/// <summary>
/// 过期时间(ms)
/// </summary>
public double? ExpiraIn { get; set; }
public IdentitySessionCacheItem() public IdentitySessionCacheItem()
{ {
@ -37,7 +60,8 @@ public class IdentitySessionCacheItem
string ipAddresses, string ipAddresses,
DateTime signedIn, DateTime signedIn,
DateTime? lastAccessed = null, DateTime? lastAccessed = null,
string ipRegion = null) string ipRegion = null,
double? expiraIn = null)
{ {
Device = device; Device = device;
DeviceInfo = deviceInfo; DeviceInfo = deviceInfo;
@ -48,6 +72,7 @@ public class IdentitySessionCacheItem
IpRegion = ipRegion; IpRegion = ipRegion;
SignedIn = signedIn; SignedIn = signedIn;
LastAccessed = lastAccessed; LastAccessed = lastAccessed;
ExpiraIn = expiraIn;
} }
public static string CalculateCacheKey(string sessionId) public static string CalculateCacheKey(string sessionId)

Loading…
Cancel
Save