天天看點

吐槽一下Abp的使用者和租戶管理子產品

吐槽一下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服務和控制器中是可以即時使用的。

吐槽一下Abp的使用者和租戶管理子產品

|

吐槽一下Abp的使用者和租戶管理子產品

2. Abp使用者、租戶管理

Abp

ICurrentUser

擷取不到正常HttpContext.User資訊,是因為使用了特定的封裝,封裝的方式我不能苟同:

以下是 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,則根本不可用。

    最差的情況也應該用個泛型,由應用決定特定身份片段的類型。

  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

    的取值邏輯:
  • 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的通用服務類、控制器類:

吐槽一下Abp的使用者和租戶管理子產品
new關鍵字顯式隐藏從基類繼承的成員

這樣我們可以繼續使用Abp架構其他能力,利用new關鍵詞我們也刻意隐藏了原有的無用CurrentUser屬性,

其他同僚也不需要額外的認知成本就可以開心地像往常一樣使用新的

CurrentUser

屬性。

本文來自部落格園,作者:{有态度的馬甲},轉載請注明原文連結:https://www.cnblogs.com/JulianHuang/p/13902901.html

歡迎關注我的原創技術、職場公衆号, 加好友談天說地,一起進化

吐槽一下Abp的使用者和租戶管理子產品

繼續閱讀