吐槽一下Abp的用户和租户管理模块
1. 背景
ASP.NET Core 基于声明的访问控制到底是什么鬼?
聊到基于声明的身份认证将 身份和签发机构分离,应用程序信任签发机构,故认可签发的身份信息。
-- | --- | --- | --- |
---|---|---|---|
Claim | B站:438962688 Name:饭思思_ | weibo:538210234 Name:饭思思van | 姓名:不详 籍贯:九江 |
ClaimsIdentity | 哔哩哔哩账户 | 微博账户 | 身份证 |
ClaimsPrincipal |
于是我们通常会有如下:
var claims = new[] { new Claim(nameof(ClaimTypes.NameIdentifier),_authData.Data["userId"].ToString(),ClaimValueTypes.String), new Claim(nameof(ClaimTypes.Name),_authData.Data["userName"].ToString(),ClaimValueTypes.String), new Claim("profileId",_authData.Data["profileId"].ToString()), new Claim("positionId",_authData.Data["positionId"].ToString()), new Claim("organizationId",_authData.Data["organizationId"].ToString()), new Claim("maxAge",_authData.Data["maxAge"].ToString()), }; // 设置身份卡片内容 、身份卡片核心Name, 这个时候HttpContext.User var identity = new ClaimsIdentity(claims, Scheme.Name,nameof(ClaimTypes.Name),nameof(ClaimTypes.Role)); Context.User = new ClaimsPrincipal(identity);
我们现在可以在Action中使用 HttpContext.User.Identity 获取声明的身份信息。
当我满心欢喜在Abp vnext中封装的ICurrentUser接口
获取身份信息,却无法获取身份信息。
ICurrentUser 封装了身份信息,用于获取有关当前活动的用户信息,已经被Abp框架默认注入。
你会在ApplicationSerive、 AbpController看到只读属性CurrentUser, 在Abp服务和控制器中是可以即时使用的。
--- | --- |
---|---|
![]() |
| |
2. Abp用户、租户管理
AbpICurrentUser
获取不到常规HttpContext.User信息,是因为使用了特定的封装,封装的方式我不能苟同:
以下是 ICurrentUser 接口的基本属性: IsAuthenticated 如果当前用户已登录(已认证),则返回 true. 如果用户尚未登录,则 Id 和 UserName 将返回 null. Id (Guid?): 当前用户的Id,如果用户未登录,返回 null. UserName (string): 当前用户的用户名称. 如果用户未登录,返回 null. TenantId (Guid?): 当前用户的租户Id. 对于多租户 应用程序很有用. 如果当前用户未分配给租户,返回 null. Email (string): 当前用户的电子邮件地址. 如果当前用户尚未登录或未设置电子邮件地址,返回 null. Roles (string[]): 当前用户的角色. 返回当前用户角色名称的字符串数组. .....
这里面有几个问题:
-
ICurrentUser将用户id、租户TenantId硬编码为
GUID
底层产生的身份id、租户id若不为GUID,则根本不可用。
最差的情况也应该用个泛型,由应用决定特定身份片段的类型。 -
ICurrentUser 修改了
IsAuthenticated
的取值逻辑:
- ASP.NET Core官方
认证类型不为空
,就认为用户认证通过。
// --- 来自asp.netcore源码:https://github.com/dotnet/runtime/blob/master/src/libraries/System.Security.Claims/src/System/Security/Claims/ClaimsIdentity.cs public virtual bool IsAuthenticated { get { return !string.IsNullOrEmpty(_authenticationType); } } .....
- Abp官方则认为
UserId不为空
,就认为用户认证通过。
// ---截取自abp官方源码:Volo.Abp.Users.CurrentUser public class CurrentUser : ICurrentUser, ITransientDependency { private static readonly Claim[] EmptyClaimsArray = new Claim[0]; public virtual bool IsAuthenticated => Id.HasValue; ..... }
- ICurrentUser修改了
UserName
的取值逻辑:
- Asp.NetCore检索声明信息中ClaimType==某个NameClaimType的Claim值, 作为身份认证卡片Identity的Name, 更灵活
- Abp 检索声明信息中ClaimType=="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name"的值,作为身份验证卡片的Name, 硬编码
Abp 将UserId、TenantId 硬编码为GUID,已经不够通用;
另外Abp强行变更了ASP.NET Core基于声明的身份验证的取值逻辑,若要我们接受,需要一点学习成本。
本次我的项目就是因为UserID、TenantId为String, 在CurrentUser中转换失败,Name也取值失败。
这样我在项目中就无法使用Abp ApplicationService、Controller的CurrentUser只读属性。
3. 针对Abp用户、租户管理的应对方法
我的策略,还是向尽量使用Abp框架,尽量做到【对修改封闭,对扩展开放】,
① 于是我仿照Abp的CurrentUser实现了适合自身项目的CurrentUser
:
public class CurrentUser: ITransientDependency { private static readonly Claim[] EmptyClaimsArray = new Claim[0]; public virtual string Id => _principalAccessor.Principal?.Claims?.FirstOrDefault(c => c.Type == nameof(ClaimTypes.NameIdentifier))?.Value; public virtual string UserName => _principalAccessor.Principal?.Claims?.FirstOrDefault(c => c.Type == nameof(ClaimTypes.Name))?.Value; public virtual string Email => _principalAccessor.Principal?.Claims?.FirstOrDefault(c => c.Type == nameof(ClaimTypes.Email))?.Value; public virtual string TenantId => _principalAccessor.Principal?.Claims?.FirstOrDefault(c => c.Type == "profileId")?.Value; public virtual string[] Roles => FindClaims("roleId").Select(c => c.Value).ToArray(); private readonly ICurrentPrincipalAccessor _principalAccessor; public CurrentUser(ICurrentPrincipalAccessor principalAccessor) { _principalAccessor = principalAccessor; } public virtual Claim FindClaim(string claimType) { return _principalAccessor.Principal?.Claims.FirstOrDefault(c => c.Type == claimType); } } }
② 编写继承自ApplicationService、AbpController的通用服务类、控制器类:
new关键字显式隐藏从基类继承的成员
这样我们可以继续使用Abp框架其他能力,利用new关键词我们也刻意隐藏了原有的无用CurrentUser属性,
其他同事也不需要额外的认知成本就可以开心地像往常一样使用新的CurrentUser
属性。
本文来自博客园,作者:{有态度的马甲},转载请注明原文链接:https://www.cnblogs.com/JulianHuang/p/13902901.html
欢迎关注我的原创技术、职场公众号, 加好友谈天说地,一起进化
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?
2019-10-30 .NET线程同步技术解读