ASP.NET Core 基于聲明的訪問控制到底是什么鬼?
從ASP.NET 4.x到ASP.NET Core,內(nèi)置身份驗證已從基于角色的訪問控制(RBAC)轉(zhuǎn)變?yōu)?code style="overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(255, 100, 65);">基于聲明的訪問控制(CBAC)。
我們常用的HttpContext.User屬性ASP.NET 4.0時代是IPrincipal類型,ASP.NETCore現(xiàn)在強化為ClaimsPrincipal類型。

本文就一起來看看這難纏的、晦澀難懂的聲明式訪問控制。
1.Claims : 聲明
聲明是基于聲明的身份驗證(claims-based authentication)的基礎(chǔ),聲明是某主題(Subject)的片段信息
聲明是個名詞,并不能說明主體可以做什么或不能做什么, 對應(yīng)現(xiàn)實生活中各種卡片上體現(xiàn)的片段信息。
使用術(shù)語“主題”是因為聲明不僅限于描述用戶,聲明可能與應(yīng)用程序,服務(wù)或設(shè)備有關(guān)。
| 主題 | Claim1 | Claim2 | Claim3 | Claim3 | Claim5 | Claim6 | Claim7 | Claim8 |
|---|---|---|---|---|---|---|---|---|
| 身份證 | 身份證號 | 姓名 | 性別 | 籍貫 | 生日 | 簽發(fā)機關(guān) | 簽發(fā)時間 | 過期時間 |
| 工作狗牌 | 姓名 | 級別 | 花名 | 身份證號 | 性別 | base地區(qū) | 入職時間 | --- |
| 王者榮耀 | 賬號 | 游戲等級 | 大區(qū) | 角色 | 氪金級別 | 年齡 | 注冊時間 | --- |
| 微信 | 微信號 | 昵稱 | 注冊時間 | 國籍 | 實名證件 | 手機號 | --- | --- |
| 車牌 | 車牌編號 | 車牌所屬人 | 車牌地區(qū) | 車牌性質(zhì) | 簽發(fā)時間 | 簽發(fā)機關(guān) | --- | --- |
| 某大保健會員卡 | 卡號 | 姓名 | 手機號 | 會員級別 | 辦卡時間 | 辦卡門店 | --- | --- |
//?聲明通過`System.Security.Claim`類表示
public?class?Claim?{
??public?string?Type?{?get;?}
??public?string?Value?{?get;?}
??public?string?ValueType?{?get;?}
??//?some?properties?have?been?omitted.
}
對比可見:每個聲明都有一個標(biāo)識片段信息類型的Type屬性、保存片段信息的Value屬性、片段信息的數(shù)據(jù)類型。
var idClaim = new Claim(“Id”,“ 1”,“Integer”);????????//?用戶ID:整形
var?dobClaim?=?new?Claim(“dob”,“04/20/2000”,“Date”);??//?生日:事件類型
var?emailClaim?=?new?Claim(nameof(ClaimTypes.Name),?mockUser.Email,nameof(ClaimValueTypes.String)),
2. Identities:身份
同一主題的聲明組合在一起,稱為ClaimsIdentity。
對應(yīng)現(xiàn)實生活中各種卡片:身份證、工作狗牌、車牌、大保健會員卡,均體現(xiàn)了某一個主題。
public?class?ClaimsIdentity?{
??public?string?Name?{?get;?}
??public?IEnumerable?Claims?{?get;?}
??public?string?AuthenticationType?{?get;?}????//?保存使用的身份驗證方法(Bearer、Basic)
??public?bool?IsAuthenticated?{?get;?}
??//?some?properties?have?been?omitted.
}

假設(shè)某WebAPI可通過其唯一ID和名稱來識別用戶。驗證從用戶收到的承載令牌(JWT等)后,我們可以創(chuàng)建ClaimsIdentity來表示它們:
ClaimsIdentity?userIdentity?=?new?ClaimsIdentity(
??new?Claim[]?{
????new?Claim("Id",?"1"),
????new?Claim("Username",?"Bert")
??},
??"Bearer"
);
//userIdentity.IsAuthenticated?==?true?since?we?passed?"Bearer"?as?AuthenticationType.
3. Principals: 主體
ClaimsIdentity可以方便地表示一個主題(一組聲明),很多時候一個主體有多個身份,就像現(xiàn)實生活中我們有個身份卡片,這個時候我們就需要錢包或者賬號管理工具(1Passwowd、LassPass),將各種身份集中在一起就是主體ClaimsPrincipal。
接上面的例子, 如果WebAPI需要確保訪客使用的設(shè)備處于白名單,則可以對訪客維護設(shè)備身份:
ClaimsIdentity?deviceIdentity?=?new?ClaimsIdentity(
??new?Claim[]?{
????new?Claim("IP",?"192.168.1.1"),
????new?Claim("Agent",?"Mozilla/5.0?(Windows?NT?6.1;?Win64;?x64;?rv:47.0)?Gecko/20100101?Firefox/47.0")
??}
);
//??針對訪客設(shè)備聲明,不要設(shè)置AuthenticationType
主體對象代表代碼運行的用戶的安全上下文,是各種有效身份的組合。
public?class?ClaimsPrincipal?{
??public?IEnumerable?Claims?{?get;?}
??public?IEnumerable?{?get;?}
??public?ClaimsIdentity?Identity?{?get;?}
??public?virtual?IEnumerable?FindAll(Predicate?match);
??public?virtual?bool?HasClaim(string?type,?string?value);
??//?ClaimsPrincipal提供了一些輔助方法/屬性來檢查聲明.
}
?var?principal?=?new?ClaimsPrincipal(new?IIdentity[]?{?userIdentity,?deviceIdentity?});
總結(jié)
基于聲明的身份驗證是WebApp獲取它們需要的組織內(nèi)部、其他組織以及Internet上的用戶的身份信息的常用方法。它還為本地或云中運行的應(yīng)用程序提供了一致的方法。基于聲明的身份驗證將身份和訪問控制的各個元素抽象為兩個部分:聲明的概念以及頒發(fā)者或授權(quán)機構(gòu)的概念。[
Claims:?身份信息的片段數(shù)據(jù) Identities:各種身份卡片 Principals:主體,各種身份賬戶的集中存儲地 


微信竟然可以查出行軌跡了,預(yù)計又一波情侶要分手?

一款開源的.NET Core爬蟲神器:DotnetSpider
