From 95aba3d268d3439b318314df68f16ceca1c76799 Mon Sep 17 00:00:00 2001 From: Young Date: Sat, 19 Oct 2024 11:37:28 +0800 Subject: [PATCH] optimise user context --- .../HttpUserContext/ClaimConstants.cs | 8 ++ .../HttpUserContext/IUserContext.cs | 33 ++++--- .../HttpUserContext/UserContext.cs | 89 ++++++++++++++++--- 3 files changed, 108 insertions(+), 22 deletions(-) create mode 100644 src/Infrastructure/HttpUserContext/ClaimConstants.cs diff --git a/src/Infrastructure/HttpUserContext/ClaimConstants.cs b/src/Infrastructure/HttpUserContext/ClaimConstants.cs new file mode 100644 index 0000000..4704fc0 --- /dev/null +++ b/src/Infrastructure/HttpUserContext/ClaimConstants.cs @@ -0,0 +1,8 @@ +namespace Infrastructure.HttpUserContext; + +public static class ClaimConstants +{ + public const string RoleId = "role_id"; + + public const string PermissionCode = "permission_code"; +} \ No newline at end of file diff --git a/src/Infrastructure/HttpUserContext/IUserContext.cs b/src/Infrastructure/HttpUserContext/IUserContext.cs index 5adcb82..18d52c9 100644 --- a/src/Infrastructure/HttpUserContext/IUserContext.cs +++ b/src/Infrastructure/HttpUserContext/IUserContext.cs @@ -1,4 +1,5 @@ using System.Security.Claims; +using Microsoft.AspNetCore.Authentication.JwtBearer; namespace Infrastructure.HttpUserContext; @@ -6,50 +7,62 @@ namespace Infrastructure.HttpUserContext; /// 用户上下文 /// /// -public interface IUserContext where TId : IEquatable +public interface IUserContext where TId : IEquatable { /// /// 用户primary key的类型 /// - TId Id { get; } + TId Id { get; set; } /// /// 用户名 /// - string Username { get; } + string Username { get; set; } /// /// 名称 /// - string Name { get; } + string Name { get; set; } /// /// 邮箱 /// - string Email { get; } + string Email { get; set; } /// /// 角色id /// - string[] RoleIds { get; } + string[] RoleIds { get; set; } + + /// + /// 角色名称 + /// + string[] RoleNames { get; set; } + + /// + /// 权限 + /// + string[] Permissions { get; set; } /// /// 访问Ip /// - string RemoteIpAddress { get; } + string RemoteIpAddress { get; set; } /// /// 生成Jwt token信息 /// - /// + /// /// /// /// - JwtTokenInfo GenerateTokenInfo(JwtSecurityToken jwtSecurityToken, double? duration, string schemeName); + JwtTokenInfo GenerateTokenInfo(IList? claims = null, + double? duration = null, + string schemeName = JwtBearerDefaults.AuthenticationScheme); /// /// 从当前用户上下文获取claims /// /// - IList GetClaimsFromUserContext(); + IList? GetClaimsFromUserContext(bool includePermissions = false); } \ No newline at end of file diff --git a/src/Infrastructure/HttpUserContext/UserContext.cs b/src/Infrastructure/HttpUserContext/UserContext.cs index cea4deb..2a8837c 100644 --- a/src/Infrastructure/HttpUserContext/UserContext.cs +++ b/src/Infrastructure/HttpUserContext/UserContext.cs @@ -24,25 +24,84 @@ public class UserContext( { private readonly ClaimsPrincipal principal = httpContextAccessor?.HttpContext?.User; - public TId Id => GetIdFromClaims(); + private TId? _id; - public string Username => principal.Claims.First(c => c.Type == JwtRegisteredClaimNames.UniqueName).Value; + private string? _username; - public string Name => principal.Claims.First(c => c.Type == JwtRegisteredClaimNames.Name).Value; + private string? _name; - public string Email => principal.Claims.First(c => c.Type == JwtRegisteredClaimNames.Email).Value; + private string? _email; - public string[] RoleIds => principal.Claims.Where(c => c.Type == ClaimTypes.Role).Select(c => c.Value).ToArray(); + private string[]? _roleIds; - public string RemoteIpAddress => httpContextAccessor.HttpContext?.GetRequestIp()!; + private string? _remoteIpAddress; + + private string[]? _roleNames; + + private string[]? _permissions; + + public TId Id + { + get => _id ??= GetIdFromClaims(); + set => _id = value; + } + + public string Username + { + get => _username ??= principal.Claims.First(c => c.Type == JwtRegisteredClaimNames.UniqueName).Value; + set => _username = value; + } + + public string Name + { + get => _name ??= principal.Claims.First(c => c.Type == JwtRegisteredClaimNames.Name).Value; + set => _name = value; + } + + public string Email + { + get => _email ??= principal.Claims.First(c => c.Type == JwtRegisteredClaimNames.Email).Value; + set => _email = value; + } + + public string[] RoleIds + { + get => _roleIds ??= principal.Claims.Where(c => c.Type == ClaimConstants.RoleId).Select(c => c.Value).ToArray(); + set => _roleIds = value; + } + + public string[] RoleNames + { + get => _roleNames ??= principal.Claims.Where(c => c.Type == ClaimTypes.Role) + .Select(c => c.Value).ToArray(); + set => _roleNames = value; + } + + public string[] Permissions + { + get => _permissions ??= principal.Claims.Where(c => c.Type == ClaimConstants.PermissionCode) + .Select(c => c.Value).ToArray(); + set => _permissions = value; + } + + public string RemoteIpAddress + { + get => _remoteIpAddress ??= httpContextAccessor.HttpContext?.GetRequestIp()!; + set => _remoteIpAddress = value; + } public JwtTokenInfo GenerateTokenInfo( - JwtSecurityToken? securityToken = null, + IList? claims = null, double? duration = null, string schemeName = JwtBearerDefaults.AuthenticationScheme) { - var claims = GetClaimsFromUserContext(); - securityToken ??= new JwtSecurityToken( + claims ??= GetClaimsFromUserContext(); + if (double.NaN == duration) + { + duration = jwtContext.Duration; + } + + var securityToken = new JwtSecurityToken( issuer: jwtContext.Issuer, audience: jwtContext.Audience, claims: claims, @@ -51,10 +110,10 @@ public class UserContext( signingCredentials: jwtContext.SigningCredentials); var token = jwtSecurityTokenHandler.WriteToken(securityToken); token = encryptionService.Encrypt(token); - return new JwtTokenInfo(token, duration ?? jwtContext.Duration, schemeName); + return new JwtTokenInfo(token, duration.Value, schemeName); } - public IList GetClaimsFromUserContext() + public IList? GetClaimsFromUserContext(bool includePermissions = false) { var claims = new List() { @@ -68,7 +127,13 @@ public class UserContext( new(JwtRegisteredClaimNames.Exp, TimeSpan.FromSeconds(jwtContext.Duration).ToString()) }; - claims.AddRange(RoleIds.Select(rId => new Claim(ClaimTypes.Role, rId))); + claims.AddRange(RoleIds.Select(rId => new Claim(ClaimConstants.RoleId, rId))); + claims.AddRange(RoleNames.Select(rName => new Claim(ClaimTypes.Role, rName))); + if (includePermissions) + { + claims.AddRange(Permissions.Select(p => new Claim(ClaimConstants.PermissionCode, p))); + } + return claims; }