ASP.NET Core 基於聲明的訪問控制到底是什麼鬼?
- 2020 年 9 月 25 日
- 筆記
從ASP.NET 4.x到ASP.NET Core,內置身份驗證已從基於角色的訪問控制(RBAC)轉變為基於聲明的訪問控制(CBAC)
。
我們常用的HttpContext.User屬性ASP.NET 4.0時代是IPrincipal類型,ASP.NETCore現在強化為ClaimsPrincipal類型。
本文就一起來看看這難纏的、晦澀難懂的聲明式訪問控制。
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<Claim> Claims { get; }
public string AuthenticationType { get; } // 保存使用的身份驗證方法(Bearer、Basic)
public bool IsAuthenticated { get; }
// some properties have been omitted.
}
某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<Claim> Claims { get; }
public IEnumerable<ClaimsIdentity> { get; }
public ClaimsIdentity Identity { get; }
public virtual IEnumerable<Claim> FindAll(Predicate<Claim> match);
public virtual bool HasClaim(string type, string value);
// ClaimsPrincipal提供了一些輔助方法/屬性來檢查事物,例如在任何關聯的身份中是否存在聲明.
}
主體對象代表代碼運行的用戶的安全上下文,是各種有效身份的組合。
var principal = new ClaimsPrincipal(new IIdentity[] { userIdentity, deviceIdentity });
總結
基於聲明的訪問控制,本質是將散落的各個主題身份收集起來,自行表徵。
-
Claims: 身份信息的片段數據
-
Identities: 各種身份信息
-
Principals: 主體,各種身份賬戶的集中存儲地
-
//eddieabbondanz.io/post/aspnet/claims-based-authentication-claims-identities-principals/