ASP.NET Core 基于声明的访问控制到底是什么鬼?
从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. }
每张身份卡片,有一个显著的Name
, 通过源码得知Name值
取自特定 _nameClaimType
:
public virtual string? Name { // just an accessor for getting the name claim get { Claim? claim = FindFirst(_nameClaimType); if (claim != null) { return claim.Value; } return null; } }
所以为确保 Identity有Name, 请传入有效的NameType
某WebAPI,该API可通过其唯一ID和名称来识别用户。验证从用户收到的承载令牌(JWT等)后,我们可以创建ClaimsIdentity
来表示它们:
ClaimsIdentity userIdentity = new ClaimsIdentity( new Claim[] { new Claim("Id", "1"), new Claim("Username", "Bert") }, "Bearer", "UserName", "Role" ); //userIdentity.IsAuthenticated == true since we passed "Bearer" as AuthenticationType. // userIdentity.Name= "Bert" since FindFirst type="UserName"
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 });
总结
基于声明的身份是应用程序用来获取有关另一个应用程序已通过身份验证的用户的身份信息的常用方法。
声明是关于用户的签发信息,这些信息已打包并签名为安全令牌,并由发行者/身份认签发机构通过安全令牌服务(STS)发送给依赖方应用程序
在基于声明的身份验证方法中,信任是显式的。您的应用程序仅在信任签发机构的情况下,才相信有关当前用户的签发信息
-
Claims: 身份信息的片段数据
-
Identities: 各种身份信息
-
Principals: 主体,各种身份账户的集中存储地
-
https://eddieabbondanz.io/post/aspnet/claims-based-authentication-claims-identities-principals/
本文来自博客园,作者:{有态度的马甲},转载请注明原文链接:https://www.cnblogs.com/JulianHuang/p/13725873.html
欢迎关注我的原创技术、职场公众号, 加好友谈天说地,一起进化
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步