1. 程式人生 > >ASP.NET Core 基於宣告的訪問控制到底是什麼鬼?

ASP.NET Core 基於宣告的訪問控制到底是什麼鬼?

從ASP.NET 4.x到ASP.NET Core,內建身份驗證已從基於角色的訪問控制(RBAC)轉變為`基於宣告的訪問控制(CBAC)`。 > 我們常用的HttpContext.User屬性ASP.NET 4.0時代是IPrincipal型別,ASP.NETCore現在強化為ClaimsPrincipal型別。 ![](https://img2020.cnblogs.com/blog/587720/202009/587720-20200925100441784-1451471742.jpg) 本文就一起來看看這難纏的、晦澀難懂的宣告式訪問控制。 ## 1.Claims : 宣告 宣告是基於宣告的身份驗證(claims-based authentication)的基礎,宣告是某`主題(Subject)`的片段資訊 > 宣告是以個名詞,並不能說明主體可以做什麼或不能做什麼, 對應現實生活中各種卡片上體現的片段資訊。 使用術語“**主題**”是因為宣告不僅限於描述使用者,宣告可能與應用程式,服務或裝置有關。 | 主題 | Claim1 | Claim2 | Claim3 | Claim3 | Claim5| Claim6 | Claim7 |Claim8 | | --- | --- | --- | --- | --- | --- | --- | --- |--- | | 身份證| 身份證號| 姓名| 性別| 籍貫 | 生日| 簽發機關| 簽發時間| 過期時間| |工作狗牌 |姓名 |級別|花名| 身份證號| 性別| base地區| 入職時間|--- | | 王者榮耀| 賬號 |遊戲等級| 大區| 角色 |氪金級別|年齡| 註冊時間| --- |--- | | 微信 | 微訊號 |暱稱| 註冊時間| 國籍| 實名證件| 手機號 |---| --- |--- | |車牌 | 車牌編號| 車牌所屬人| 車牌地區| 車牌性質| 簽發時間| 簽發機關|--- |--- | | 某大保健會員卡 |卡號| 姓名| 手機號| 會員級別| 辦卡時間| 辦卡門店 |--- |--- | ``` // 宣告通過`System.Security.Claim`類表示。 public class Claim { public string Type { get; } public string Value { get; } public string ValueType { get; } // some properties have been omitted. } ``` 對比可見:每個宣告都有一個標識片段資訊型別的Type屬性、儲存片段資訊的Value屬性、片段資訊的資料型別。 ``` 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。 > 對應現實生活中**各種卡片**:身份證、工作狗牌、車牌、大保健會員卡,均體現了某一個主題。 ``` 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. } ``` ![](https://img2020.cnblogs.com/blog/587720/202009/587720-20200925100518457-565096826.png) 某WebAPI,該API可通過其唯一ID和名稱來識別使用者。驗證從使用者收到的承載令牌(JWT等)後,我們可以建立`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`可以方便地表示一個主題(一組宣告),很多時候一個主體有多個身份,就像現實生活中我們有個身份卡片,這個時候我們就需要**錢包或者賬號管理工具**(1Passwowd、LassPass) 接上面的例子, 如果WebAPI需要確保訪客使用的裝置處於白名單,則可以對訪客維護`裝置身份`: ``` 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") } ); // 針對訪客裝置宣告,不要設定AuthenticationType ``` 將`使用者身份`和`裝置身份`兩個獨立的身份集中在一起就是`主體ClaimsPrincipal` ``` 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 }); ``` ## 總結 基於宣告的訪問控制,本質是將散落的各個主題身份收集起來,自行表徵。 - Claims: 身份資訊的片段資料 - Identities: 各種身份資訊 - Principals: 主體,各種身份賬戶的集中儲存地 ![](https://img2020.cnblogs.com/blog/587720/202009/587720-20200925100559798-1863669041.png) - https://github.com/dotnet/runtime/blob/master/src/libraries/System.Security.Claims/src/System/Security/Claims/ClaimsIdentity.cs - https://eddieabbondanz.io/post/aspnet/claims-based-authentication-claims-identities-pri