Browse Source

Add `IdentitySessionManager`.

pull/18242/head
maliming 3 years ago
parent
commit
3d91733bc1
No known key found for this signature in database GPG Key ID: A646B9CB645ECEA4
  1. 33
      framework/src/Volo.Abp.Security/System/Security/Principal/AbpClaimsIdentityExtensions.cs
  2. 8
      framework/src/Volo.Abp.Security/Volo/Abp/Security/Claims/AbpClaimTypes.cs
  3. 22
      framework/src/Volo.Abp.Security/Volo/Abp/Users/CurrentUserExtensions.cs
  4. 6
      modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/IdentitySessionConsts.cs
  5. 8
      modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/IdentitySessionDevices.cs
  6. 11
      modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IIdentitySessionRepository.cs
  7. 15
      modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentitySession.cs
  8. 98
      modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentitySessionManager.cs
  9. 37
      modules/identity/src/Volo.Abp.Identity.EntityFrameworkCore/Volo/Abp/Identity/EntityFrameworkCore/EfCoreIdentitySessionRepository.cs
  10. 5
      modules/identity/src/Volo.Abp.Identity.EntityFrameworkCore/Volo/Abp/Identity/EntityFrameworkCore/IdentityDbContextModelBuilderExtensions.cs
  11. 41
      modules/identity/src/Volo.Abp.Identity.MongoDB/Volo/Abp/Identity/MongoDB/MongoIdentitySessionRepository.cs

33
framework/src/Volo.Abp.Security/System/Security/Principal/AbpClaimsIdentityExtensions.cs

@ -276,4 +276,37 @@ public static class AbpClaimsIdentityExtensions
return principal; return principal;
} }
public static Guid? FindSessionId([NotNull] this IIdentity identity)
{
Check.NotNull(identity, nameof(identity));
var claimsIdentity = identity as ClaimsIdentity;
var sessionIdOrNull = claimsIdentity?.Claims?.FirstOrDefault(c => c.Type == AbpClaimTypes.SessionId);
if (sessionIdOrNull == null || sessionIdOrNull.Value.IsNullOrWhiteSpace())
{
return null;
}
if (Guid.TryParse(sessionIdOrNull.Value, out var guid))
{
return guid;
}
return null;
}
public static string? FindSessionId([NotNull] this ClaimsPrincipal principal)
{
Check.NotNull(principal, nameof(principal));
var sessionIdOrNull = principal.Claims?.FirstOrDefault(c => c.Type == AbpClaimTypes.SessionId);
if (sessionIdOrNull == null || sessionIdOrNull.Value.IsNullOrWhiteSpace())
{
return null;
}
return sessionIdOrNull.Value;
}
} }

8
framework/src/Volo.Abp.Security/Volo/Abp/Security/Claims/AbpClaimTypes.cs

@ -87,9 +87,15 @@ public static class AbpClaimTypes
/// Default: "impersonator_username". /// Default: "impersonator_username".
/// </summary> /// </summary>
public static string ImpersonatorUserName { get; set; } = "impersonator_username"; public static string ImpersonatorUserName { get; set; } = "impersonator_username";
/// <summary> /// <summary>
/// Default: "picture". /// Default: "picture".
/// </summary> /// </summary>
public static string Picture { get; set; } = "picture"; public static string Picture { get; set; } = "picture";
/// <summary>
/// Default: "session_id".
/// </summary>
public static string SessionId { get; set; } = "session_id";
} }

22
framework/src/Volo.Abp.Security/Volo/Abp/Users/CurrentUserExtensions.cs

@ -70,4 +70,26 @@ public static class CurrentUserExtensions
{ {
return currentUser.FindClaimValue(AbpClaimTypes.ImpersonatorUserName); return currentUser.FindClaimValue(AbpClaimTypes.ImpersonatorUserName);
} }
public static Guid GetSessionId([NotNull] this ICurrentUser currentUser)
{
var sessionId = currentUser.FindSessionId();
Debug.Assert(sessionId != null, "sessionId != null");
return sessionId!.Value;
}
public static Guid? FindSessionId([NotNull] this ICurrentUser currentUser)
{
var sessionId = currentUser.FindClaimValue(AbpClaimTypes.SessionId);
if (sessionId.IsNullOrWhiteSpace())
{
return null;
}
if (Guid.TryParse(sessionId, out var guid))
{
return guid;
}
return null;
}
} }

6
modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/IdentitySessionConsts.cs

@ -2,7 +2,11 @@ namespace Volo.Abp.Identity;
public class IdentitySessionConsts public class IdentitySessionConsts
{ {
public static int MaxDeviceLength { get; set; } = 128; public static int MaxSessionIdLength { get; set; } = 128;
public static int MaxDeviceLength { get; set; } = 64;
public static int MaxDeviceInfoLength { get; set; } = 64;
public static int MaxClientIdLength { get; set; } = 64; public static int MaxClientIdLength { get; set; } = 64;

8
modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/IdentitySessionDevices.cs

@ -0,0 +1,8 @@
namespace Volo.Abp.Identity;
public static class IdentitySessionDevices
{
public const string Web = "Web";
public const string OAuth = "OAuth";
}

11
modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IIdentitySessionRepository.cs

@ -1,9 +1,20 @@
using System; using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using Volo.Abp.Domain.Repositories; using Volo.Abp.Domain.Repositories;
namespace Volo.Abp.Identity; namespace Volo.Abp.Identity;
public interface IIdentitySessionRepository : IBasicRepository<IdentitySession, Guid> public interface IIdentitySessionRepository : IBasicRepository<IdentitySession, Guid>
{ {
Task<IdentitySession> FindAsync(string sessionId, CancellationToken cancellationToken = default);
Task<IdentitySession> GetAsync(string sessionId, CancellationToken cancellationToken = default);
Task<List<IdentitySession>> GetListAsync(Guid userId, CancellationToken cancellationToken = default);
Task DeleteAllAsync(Guid userId, Guid? exceptSessionId = null, CancellationToken cancellationToken = default);
Task DeleteAllAsync(Guid userId, string device, Guid? exceptSessionId = null, CancellationToken cancellationToken = default);
} }

15
modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentitySession.cs

@ -1,16 +1,21 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using Volo.Abp.Domain.Entities; using Volo.Abp.Domain.Entities;
using Volo.Abp.MultiTenancy;
namespace Volo.Abp.Identity; namespace Volo.Abp.Identity;
public class IdentitySession : BasicAggregateRoot<Guid> public class IdentitySession : BasicAggregateRoot<Guid>, IMultiTenant
{ {
public virtual string SessionId { get; protected set; }
/// <summary> /// <summary>
/// Web, CLI, STUDIO, ... /// Web, OAuth ...
/// </summary> /// </summary>
public virtual string Device { get; protected set; } public virtual string Device { get; protected set; }
public virtual string DeviceInfo { get; protected set; }
public virtual Guid? TenantId { get; protected set; } public virtual Guid? TenantId { get; protected set; }
public virtual Guid UserId { get; protected set; } public virtual Guid UserId { get; protected set; }
@ -30,16 +35,20 @@ public class IdentitySession : BasicAggregateRoot<Guid>
public IdentitySession( public IdentitySession(
Guid id, Guid id,
string sessionId,
string device, string device,
string deviceInfo,
Guid userId, Guid userId,
Guid? tenantId, Guid? tenantId,
string clientId, string clientId,
string ipAddresses, string ipAddresses,
DateTime signedIn, DateTime signedIn,
DateTime? lastAccessed) DateTime? lastAccessed = null)
{ {
Id = id; Id = id;
SessionId = sessionId;
Device = device; Device = device;
DeviceInfo = deviceInfo;
UserId = userId; UserId = userId;
TenantId = tenantId; TenantId = tenantId;
ClientId = clientId; ClientId = clientId;

98
modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentitySessionManager.cs

@ -0,0 +1,98 @@
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Volo.Abp.Domain.Services;
using Volo.Abp.Users;
namespace Volo.Abp.Identity;
public class IdentitySessionManager : DomainService
{
protected IIdentitySessionRepository IdentitySessionRepository { get; }
protected ICurrentUser CurrentUser { get; }
public IdentitySessionManager(IIdentitySessionRepository identitySessionRepository, ICurrentUser currentUser)
{
IdentitySessionRepository = identitySessionRepository;
CurrentUser = currentUser;
}
public virtual async Task<IdentitySession> CreateAsync(
string sessionId,
string device,
string deviceInfo,
Guid userId,
Guid? tenantId,
string clientId,
string ipAddresses)
{
Check.NotNullOrWhiteSpace(sessionId, nameof(sessionId));
Check.NotNullOrWhiteSpace(device, nameof(device));
var session = new IdentitySession(
GuidGenerator.Create(),
sessionId,
device,
deviceInfo,
userId,
tenantId,
clientId,
ipAddresses,
Clock.Now
);
return await IdentitySessionRepository.InsertAsync(session);
}
public virtual async Task UpdateAsync(IdentitySession session)
{
await IdentitySessionRepository.UpdateAsync(session);
}
public virtual async Task<List<IdentitySession>> GetListAsync(Guid userId)
{
return await IdentitySessionRepository.GetListAsync(userId);
}
public virtual async Task<IdentitySession> GetAsync(Guid id)
{
return await IdentitySessionRepository.GetAsync(id);
}
public virtual async Task<IdentitySession> FindAsync(Guid id)
{
return await IdentitySessionRepository.FindAsync(id);
}
public virtual async Task<IdentitySession> GetAsync(string sessionId)
{
return await IdentitySessionRepository.GetAsync(sessionId);
}
public virtual async Task<IdentitySession> FindAsync(string sessionId)
{
return await IdentitySessionRepository.FindAsync(sessionId);
}
public virtual async Task RevokeAsync(Guid id)
{
var session = await IdentitySessionRepository.GetAsync(id);
await IdentitySessionRepository.DeleteAsync(session);
}
public virtual async Task RevokeAsync(string sessionId)
{
var session = await IdentitySessionRepository.GetAsync(sessionId);
await IdentitySessionRepository.DeleteAsync(session);
}
public virtual async Task RevokeAllAsync(Guid userId, Guid? exceptSessionId = null)
{
await IdentitySessionRepository.DeleteAllAsync(userId, exceptSessionId);
}
public virtual async Task RevokeAllAsync(Guid userId, string device, Guid? exceptSessionId = null)
{
await IdentitySessionRepository.DeleteAllAsync(userId, device, exceptSessionId);
}
}

37
modules/identity/src/Volo.Abp.Identity.EntityFrameworkCore/Volo/Abp/Identity/EntityFrameworkCore/EfCoreIdentitySessionRepository.cs

@ -1,4 +1,11 @@
using System; using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Dynamic.Core;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore;
using Volo.Abp.Domain.Entities;
using Volo.Abp.Domain.Repositories.EntityFrameworkCore; using Volo.Abp.Domain.Repositories.EntityFrameworkCore;
using Volo.Abp.EntityFrameworkCore; using Volo.Abp.EntityFrameworkCore;
@ -12,4 +19,34 @@ public class EfCoreIdentitySessionRepository : EfCoreRepository<IIdentityDbConte
} }
public virtual async Task<IdentitySession> FindAsync(string sessionId, CancellationToken cancellationToken = default)
{
return await (await GetDbSetAsync()).FirstOrDefaultAsync(x => x.SessionId == sessionId, GetCancellationToken(cancellationToken));
}
public virtual async Task<IdentitySession> GetAsync(string sessionId, CancellationToken cancellationToken = default)
{
var session = await FindAsync(sessionId, cancellationToken);
if (session == null)
{
throw new EntityNotFoundException(typeof(IdentitySession));
}
return session;
}
public virtual async Task<List<IdentitySession>> GetListAsync(Guid userId, CancellationToken cancellationToken = default)
{
return await (await GetDbSetAsync()).Where(x => x.UserId == userId).ToListAsync(GetCancellationToken(cancellationToken));
}
public virtual async Task DeleteAllAsync(Guid userId, Guid? exceptSessionId = null, CancellationToken cancellationToken = default)
{
await DeleteDirectAsync(x => x.UserId == userId && x.Id != exceptSessionId, cancellationToken);
}
public virtual async Task DeleteAllAsync(Guid userId, string device, Guid? exceptSessionId = null, CancellationToken cancellationToken = default)
{
await DeleteDirectAsync(x => x.UserId == userId && x.Device == device && x.Id != exceptSessionId, cancellationToken);
}
} }

5
modules/identity/src/Volo.Abp.Identity.EntityFrameworkCore/Volo/Abp/Identity/EntityFrameworkCore/IdentityDbContextModelBuilderExtensions.cs

@ -285,11 +285,14 @@ public static class IdentityDbContextModelBuilderExtensions
b.ConfigureByConvention(); b.ConfigureByConvention();
b.Property(x => x.SessionId).HasMaxLength(IdentitySessionConsts.MaxSessionIdLength).IsRequired();
b.Property(x => x.Device).HasMaxLength(IdentitySessionConsts.MaxDeviceLength).IsRequired(); b.Property(x => x.Device).HasMaxLength(IdentitySessionConsts.MaxDeviceLength).IsRequired();
b.Property(x => x.DeviceInfo).HasMaxLength(IdentitySessionConsts.MaxDeviceInfoLength);
b.Property(x => x.ClientId).HasMaxLength(IdentitySessionConsts.MaxClientIdLength); b.Property(x => x.ClientId).HasMaxLength(IdentitySessionConsts.MaxClientIdLength);
b.Property(x => x.IpAddresses).HasMaxLength(IdentitySessionConsts.MaxIpAddressesLength); b.Property(x => x.IpAddresses).HasMaxLength(IdentitySessionConsts.MaxIpAddressesLength);
b.HasIndex(x => new { x.Device }); b.HasIndex(x => x.SessionId);
b.HasIndex(x => x.Device );
b.HasIndex(x => new { x.TenantId, x.UserId }); b.HasIndex(x => new { x.TenantId, x.UserId });
b.ApplyObjectExtensionMappings(); b.ApplyObjectExtensionMappings();

41
modules/identity/src/Volo.Abp.Identity.MongoDB/Volo/Abp/Identity/MongoDB/MongoIdentitySessionRepository.cs

@ -1,4 +1,10 @@
using System; using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using MongoDB.Driver;
using MongoDB.Driver.Linq;
using Volo.Abp.Domain.Entities;
using Volo.Abp.Domain.Repositories.MongoDB; using Volo.Abp.Domain.Repositories.MongoDB;
using Volo.Abp.MongoDB; using Volo.Abp.MongoDB;
@ -11,4 +17,39 @@ public class MongoIdentitySessionRepository : MongoDbRepository<IAbpIdentityMong
{ {
} }
public virtual async Task<IdentitySession> FindAsync(string sessionId, CancellationToken cancellationToken = default)
{
return await (await GetMongoQueryableAsync(GetCancellationToken(cancellationToken)))
.As<IMongoQueryable<IdentitySession>>()
.FirstOrDefaultAsync(x => x.SessionId == sessionId, GetCancellationToken(cancellationToken));
}
public virtual async Task<IdentitySession> GetAsync(string sessionId, CancellationToken cancellationToken = default)
{
var session = await FindAsync(sessionId, cancellationToken);
if (session == null)
{
throw new EntityNotFoundException(typeof(IdentitySession));
}
return session;
}
public virtual async Task<List<IdentitySession>> GetListAsync(Guid userId, CancellationToken cancellationToken = default)
{
return await (await GetMongoQueryableAsync(GetCancellationToken(cancellationToken)))
.As<IMongoQueryable<IdentitySession>>()
.Where(x => x.UserId == userId).ToListAsync(GetCancellationToken(cancellationToken));
}
public virtual async Task DeleteAllAsync(Guid userId, Guid? exceptSessionId = null, CancellationToken cancellationToken = default)
{
await DeleteDirectAsync(x => x.UserId == userId && x.Id != exceptSessionId, cancellationToken);
}
public virtual async Task DeleteAllAsync(Guid userId, string device, Guid? exceptSessionId = null, CancellationToken cancellationToken = default)
{
await DeleteDirectAsync(x => x.UserId == userId && x.Device == device && x.Id != exceptSessionId, cancellationToken);
}
} }

Loading…
Cancel
Save