吐槽一下Abp的用戶和租戶管理模塊

1. 背景
原創(chuàng)文《SP.NET Core 基于聲明的訪問(wèn)控制到底是什么鬼?》
聊到基于聲明的身份認(rèn)證將 身份和簽發(fā)機(jī)構(gòu)分離,應(yīng)用程序信任簽發(fā)機(jī)構(gòu),故認(rèn)可簽發(fā)的身份信息。
| -- | --- | --- | --- |
|---|---|---|---|
| Claim | B站:438962688 Name:飯思思_ | weibo:538210234 Name:飯思思van | 姓名:不詳 籍貫:九江 |
| ClaimsIdentity | 嗶哩嗶哩賬戶 | 微博賬戶 | 身份證 |
| ClaimsPrincipal |
于是我們通常會(huì)有如下:
?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()),
????};
????//?設(shè)置身份卡片內(nèi)容?、身份卡片核心Name,?這個(gè)時(shí)候HttpContext.User
???var?identity?=?new?ClaimsIdentity(claims,?Scheme.Name,nameof(ClaimTypes.Name),nameof(ClaimTypes.Role));
???Context.User?=?new?ClaimsPrincipal(identity);
我們現(xiàn)在可以在Action中使用 HttpContext.User.Identity 獲取聲明的身份信息。
當(dāng)我滿心歡喜在Abp vnext中封裝的ICurrentUser接口獲取身份信息,卻無(wú)法獲取身份信息。
ICurrentUser 封裝了身份信息,用于獲取有關(guān)當(dāng)前活動(dòng)的用戶信息,已經(jīng)被Abp框架默認(rèn)注入。
你會(huì)在ApplicationSerive、 AbpController看到屬性CurrentUser, 在Abp服務(wù)和控制器中是可以即時(shí)使用的。
| --- | --- |
|---|---|
![]() | ![]() |
2. Abp用戶、租戶管理
AbpICurrentUser獲取不到常規(guī)HttpContext.User信息,是因?yàn)槭褂昧颂囟ǖ姆庋b,封裝的方式我不能茍同:
以下是?ICurrentUser?接口的基本屬性:
IsAuthenticated?如果當(dāng)前用戶已登錄(已認(rèn)證),則返回?true.?如果用戶尚未登錄,則?Id?和?UserName?將返回?null.
Id?(Guid?):?當(dāng)前用戶的Id,如果用戶未登錄,返回?null.
UserName?(string):?當(dāng)前用戶的用戶名稱.?如果用戶未登錄,返回?null.
TenantId?(Guid?):?當(dāng)前用戶的租戶Id.?對(duì)于多租戶?應(yīng)用程序很有用.?如果當(dāng)前用戶未分配給租戶,返回?null.
Email?(string):?當(dāng)前用戶的電子郵件地址.?如果當(dāng)前用戶尚未登錄或未設(shè)置電子郵件地址,返回?null.
Roles?(string[]):?當(dāng)前用戶的角色.?返回當(dāng)前用戶角色名稱的字符串?dāng)?shù)組.
.....
這里面有幾個(gè)問(wèn)題:
①? ? ICurrentUser將用戶id、租戶TenantId硬編碼為GUID
項(xiàng)目原始的身份id、租戶id若不為GUID,則根本不可用。
最差的情況也應(yīng)該用個(gè)泛型,由應(yīng)用決定特定身份片段的類型。
②? ? ? ICurrentUser 修改了IsAuthenticated的取值邏輯
ASP.NET Core官方 認(rèn)證類型不為空,就認(rèn)為用戶認(rèn)證通過(guò)。
???//?---?來(lái)自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官方則認(rèn)為 UserId不為空,就認(rèn)為用戶認(rèn)證通過(guò)。
???//?---截取自abp官方源碼:Volo.Abp.Users.CurrentUser
????public?class?CurrentUser?:?ICurrentUser,?ITransientDependency
????{
????????private?static?readonly?Claim[]?EmptyClaimsArray?=?new?Claim[0];
????????public?virtual?bool?IsAuthenticated?=>?Id.HasValue;
????????.....
????}
UserName的取值邏輯Asp.NetCore檢索聲明信息中ClaimType==某個(gè)NameClaimType的Claim值, 作為身份認(rèn)證卡片Identity的Name, 更靈活 Abp 檢索聲明信息中ClaimType=="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name"的值,作為身份驗(yàn)證卡片的Name, 硬編碼
Abp 將UserId、TenantId 硬編碼為GUID,已經(jīng)不夠通用;??
另外Abp強(qiáng)行變更了ASP.NET Core基于聲明的身份驗(yàn)證的取值邏輯,若要我們接受,需要一點(diǎn)學(xué)習(xí)成本。
本次我的項(xiàng)目就是因?yàn)閁serID、TenantId為String, ?在Abp CurrentUser中轉(zhuǎn)換失敗;Name也取值失敗。??
在項(xiàng)目中就無(wú)法愉快地使用Abp ApplicationService、AbpController的CurrentUser屬性。
3. 針對(duì)Abp用戶、租戶管理的應(yīng)對(duì)方法
我的策略:還是向盡量使用Abp框架,盡量做到【對(duì)修改封閉,對(duì)擴(kuò)展開放】,
① 于是我仿照Abp的CurrentUser實(shí)現(xiàn)了適合自身項(xiàng)目的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的通用服務(wù)類、控制器類,使用新User類

new關(guān)鍵字顯式隱藏從基類繼承的成員
這樣我們既可以使用 Abp框架其他能力,利用new關(guān)鍵詞我們也刻意隱藏了框架原有的ICurrentUser屬性,
其他同事也不需要額外的認(rèn)知成本就可以開心地像往常一樣使用CurrentUser屬性。
學(xué)習(xí)福利
極客時(shí)間雙11,新用戶首單1元
肖老師的這個(gè)課上線的時(shí)候我就推薦過(guò),現(xiàn)在全集了,原價(jià) 129,現(xiàn)在首單用戶只要 1 塊錢,太值了,掃碼搶吧



課程目錄

直接掃碼購(gòu)買,新用戶首單只需要1元
雙11活動(dòng)
點(diǎn)擊「閱讀原文」,拿下?.NET Core!


