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

1. 背景

ASP.NET Core 基于声明的访问控制究竟是什么鬼?git

聊到基于声明的身份认证将 身份和签发机构分离,应用程序信任签发机构,故承认签发的身份信息。github

-- --- --- ---
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接口获取身份信息,却没法获取身份信息。asp.net

ICurrentUser 封装了身份信息,用于获取有关当前活动的用户信息,已经被Abp框架默认注入。
你会在ApplicationSerive、 AbpController看到只读属性CurrentUser, 在Abp服务和控制器中是能够即时使用的。ide

--- ---

| |学习

2. Abp用户、租户管理

AbpICurrentUser获取不到常规HttpContext.User信息,是由于使用了特定的封装,封装的方式我不能苟同:ui

如下是 ICurrentUser 接口的基本属性:

IsAuthenticated 若是当前用户已登陆(已认证),则返回 true. 若是用户还没有登陆,则 Id 和 UserName 将返回 null.
Id (Guid?): 当前用户的Id,若是用户未登陆,返回 null.
UserName (string): 当前用户的用户名称. 若是用户未登陆,返回 null.
TenantId (Guid?): 当前用户的租户Id. 对于多租户 应用程序颇有用. 若是当前用户未分配给租户,返回 null.
Email (string): 当前用户的电子邮件地址. 若是当前用户还没有登陆或未设置电子邮件地址,返回 null.
Roles (string[]): 当前用户的角色. 返回当前用户角色名称的字符串数组.
.....

这里面有几个问题:编码

  1. ICurrentUser将用户id、租户TenantId硬编码为GUID
    底层产生的身份id、租户id若不为GUID,则根本不可用。
    最差的状况也应该用个泛型,由应用决定特定身份片断的类型。.net

  2. 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;
        .....
    }
  1. ICurrentUser修改了UserName的取值逻辑:

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属性。

相关文章
相关标签/搜索