吐槽一下Abp的用户和租户管理模块

简介: 我们既可以使用 Abp框架其他能力,利用new关键词我们也刻意隐藏了框架原有的ICurrentUser属性

1. 背景


原创文《SP.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服务和控制器中是可以即时使用的。

f8377c40126b4ee34eb57d6337086002.png40190410336456ae8740ecde9595ec82.png

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,  在Abp CurrentUser中转换失败;Name也取值失败。  


在项目中就无法愉快地使用Abp ApplicationService、AbpController的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的通用服务类、控制器类,使用新User类


518422e7a5cb33668bb26ff6b0d5ed09.png


new关键字显式隐藏从基类继承的成员


这样我们既可以使用 Abp框架其他能力,利用new关键词我们也刻意隐藏了框架原有的ICurrentUser属性,


其他同事也不需要额外的认知成本就可以开心地像往常一样使用CurrentUser属性。

相关文章
|
监控 架构师 Java
JVM 11 调优指南:如何进行JVM调优,JVM调优参数
JVM 11的优化指南:如何进行JVM调优,以及JVM调优参数有哪些”这篇文章将包含JVM 11调优的核心概念、重要性、调优参数,并提供12个实用的代码示例,每个示例都会结合JVM调优参数和Java代码
684 2
|
API
.net core工具组件系列之Autofac—— 第二篇:Autofac的3种依赖注入方式(构造函数注入、属性注入和方法注入),以及在过滤器里面实现依赖注入
本篇文章接前一篇,建议可以先看前篇文章,再看本文,会有更好的效果。前一篇跳转链接:https://www.cnblogs.com/weskynet/p/15046999.html
1226 0
.net core工具组件系列之Autofac—— 第二篇:Autofac的3种依赖注入方式(构造函数注入、属性注入和方法注入),以及在过滤器里面实现依赖注入
|
开发框架 缓存 前端开发
基于SqlSugar的开发框架循序渐进介绍(4)-- 在数据访问基类中对GUID主键进行自动赋值处理
基于SqlSugar的开发框架循序渐进介绍(4)-- 在数据访问基类中对GUID主键进行自动赋值处理
|
10月前
|
XML JSON API
如何从 Swagger 导出 API 文档
Swagger 使这项任务相对简单,允许开发者以各种格式(如 JSON 和 YAML)导出 API 文档。在这篇博文中,我们将详细探讨如何从 Swagger 导出 API 文档。
如何从 Swagger 导出 API 文档
|
存储 开发框架 .NET
程序与技术分享:ABP之多租户
程序与技术分享:ABP之多租户
498 0
|
缓存 测试技术 C#
使用Radzen Blazor组件库开发的基于ABP框架炫酷UI主题
【10月更文挑战第20天】本文介绍了使用 Radzen Blazor 组件库开发基于 ABP 框架的炫酷 UI 主题的步骤。从准备工作、引入组件库、设计主题、集成到 ABP 框架,再到优化和调试,详细讲解了每个环节的关键点和注意事项。通过这些步骤,你可以打造出高性能、高颜值的应用程序界面。
559 1
|
开发框架 前端开发 JavaScript
在ABP VNext框架中对HttpApi模块的控制器进行基类封装
在ABP VNext框架中对HttpApi模块的控制器进行基类封装
|
开发框架 前端开发 JavaScript
ABP开发框架的技术点分析(1)
ABP开发框架的技术点分析(1)
|
存储 开发框架 前端开发
Abp源码分析之虚拟文件系统Volo.Abp.VirtualFileSystem
`Volo.Abp.VirtualFileSystem` 是 ABP 框架中的一个重要组件,提供了一种抽象文件系统的方式,使应用程序可以轻松访问和管理文件资源。本文介绍了如何在 MVC 项目中使用 `Volo.Abp.VirtualFileSystem`,包括新建项目、配置模块、添加资源文件以及读取资源文件的具体步骤。通过统一的接口处理文件和目录,无论实际存储位置如何,应用程序都能更加灵活地切换不同的文件存储方式。
282 0
Abp源码分析之虚拟文件系统Volo.Abp.VirtualFileSystem
|
开发框架 中间件 API
ABP VNext框架基础知识介绍(2)--微服务的网关
ABP VNext框架基础知识介绍(2)--微服务的网关

热门文章

最新文章