吐槽一下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关键词我们也刻意覆盖了原有的ICurrentUser属性,
其他同事也不需要额外的认知成本就可以开心地像往常一样使用CurrentUser
属性。
吐槽一下Abp的用户和租户管理模块的更多相关文章
- 初识ABP vNext(7):vue身份认证管理&租户管理
Tips:本篇已加入系列文章阅读目录,可点击查看更多相关文章. 目录 前言 开始 按钮级权限 身份认证管理 R/U权限 权限刷新 租户管理 租户切换 效果 最后 前言 上一篇介绍了vue+ABP国际化 ...
- ABP Zero 多租户管理
ABPZero - 多租户管理 启用多租户 ASP.NET Boilerplate和module-zero可以运行多租户或单租户模式.多租户默认为禁用.我们可以在我们的模块PreInitialize方 ...
- X-Admin&ABP框架开发-租户管理
软件即服务概念的推动,定制化到通用化的发展,用一套代码完成适应不同企业的需求,利用多租户技术可以去做到这一点.ABP里提供了多租户这一概念并且也在Zero模块中实现了这一概念. 一.多租户的概念 单部 ...
- Oracle12c多租户管理用户、角色、权限
Oracle 数据库 12 c 多租户选项允许单个容器数据库 (CDB) 来承载多个单独的可插拔数据库 (PDB).那么我们如何在容器数据库 (CDB) 和可插拔数据库 (PDB)管理用户权限.背景: ...
- ABP理论学习之多租户
返回总目录 本篇目录 什么是多租户 ABP中的多租户 什么是多租户 维基百科:"软件多租户是指一种软件架构,在这种软件架构中,软件的一个实例运行在服务器上并且为多个租户服务".一个 ...
- 详解ABP框架的多租户
(此文章同时发表在本人微信公众号"dotNET每日精华文章",欢迎右边二维码来关注.) 题记:ABP框架对多租户场景提供了很好的支持,内建了多租户的处理机制,今天我们来深入解析一下 ...
- 番外篇--Moddule Zero多租户管理
番外篇--Moddule Zero多租户管理 2.1.1 关于多租户 强烈建议阅读这个文件前阅读多租户文档. 2.1.2 启用多租户 ASP.NET Boilerplate和module-zero可以 ...
- 分享一个基于 ABP(.NET 5.0) + vue-element-admin 管理后台
1.前言 分享一个基于ABP(.NET 5.0) + vue-element-admin项目.希望可以降低新手对于ABP框架的学习成本,感兴趣的同学可以下载项目启动运行一下.对于想选型采用ABP框架的 ...
- 在vCenter5.5中为用户创建角色,管理虚拟机
在vSphere的使用中,如有只有vCenter+ESXi节点的两级配置,为了达到多租户管理及权限分配,可以在vCenter5.5中为用户创建角色,管理虚拟机 1.以管理员身份登陆vCenter 2. ...
随机推荐
- 从GitHub建站迁移到服务器(Java环境)
一.购买域名和服务器 域名:阿里云:lookabc.cn 服务器:腾讯云,学生价格便宜 二.域名解析 注意:由于域名和服务器不在同一家,需要域名迁入和迁出 三.搭建服务器环境 1.下载xftp6和xs ...
- 小程序开发-iView app的NoticeBar 通告栏修改背景颜色
NoticeBar 通告栏 这是个比较好用的组件,具体使用方法见 http://inmap.talkingdata.com/wx/index_prod.html#/components/notice- ...
- IDM下载度盘文件
百度网盘是百度公司推出的一款个人云服务产品.百度网盘官方版操作简单,我们打开后就可以使用该软件来上传.下载文件等.不仅如此百度网盘软件还可以批量上传文件.支持断点传续等功能,重要的是上传的文件不会占用 ...
- 【转载】C/走迷宫代码
1 #include<iostream> 2 #include<windows.h> 3 #include"GotoXY.h" 4 #include < ...
- 电机AB相编码器测速
控制任务 检测编码器的脉冲并测速 电路设计 图1 直流电机带减速器和编码器 图2 编码器接线定义 编码器接线定义如下 M1:电机电源接口,绿色的 GND:编码器电源负极输入口,橙色的 C1:编码器A ...
- Code Forces 1030E
题目大意: 给你n个数,你可以交换一个数的任意二进制位,问你可以选出多少区间经过操作后异或和是0. 思路分析: 根据题目,很容易知道,对于每个数,我们可以无视它的1在那些位置,只要关注它有几个1即可, ...
- 2020年了,IT外企还香吗?
本来是刚发了<世上有不用加班的程序员吗?>,有朋友问到IT外企不加班福利好什么的,就回复了几句. 老王观点: 现在IT外企已经不值得羡慕了,08.09年那会,ibm,惠普还是香饽饽,当时人 ...
- 打印一个N*N的方阵,N为每边字符的个数( 3〈N〈20 ),写出来真是泪牛满面啊。
本程序可以完美输出,效果如下: 相信你已经很期待代码实现了吧,其实代码真的不难,关键是思想.我说说我的想法吧,首先我构造了一个数组,保存了上面图片中字符一行的一半.聪明的你肯定看出来了,上面多数字符都 ...
- spring boot:使用多个redis数据源(spring boot 2.3.1)
一,什么情况下需要使用多个redis数据源? 为了缓存数据,通常我们会在线上使用多个redis的cluster, 每个cluster中缓存不同的数据,以方便管理. 例如:我们缓存了杂志文章/商品信息/ ...
- centos8上redis5在生产环境的配置
一,创建redis的数据和日志目录: [root@yjweb data]# mkdir /data/redis6379 [root@yjweb data]# mkdir /data/redis6379 ...