具有角色的授权属性是否考虑了声明

does Authorize attribute with Roles take Claims into account

我在网上到处搜索,但我似乎无法弄清楚这个重要部分。

基本上,如果我们每次检查用户是否属于某个角色时都调用数据库 - 这会对性能产生负面影响。

我看到了列出所有用户角色的代码示例,例如

var roles = ((ClaimsIdentity)User.Identity).Claims
            .Where(c => c.Type == ClaimTypes.Role)
            .Select(c => c.Value);

代码可用于控制器操作,也可以在属性过滤器中以相同方式获取声明。

从这个例子中我推断 Claims 发挥作用(似乎是最高效的解决方案)。

我试图找出 if Authorize 具有角色的属性验证用户的声明,但是 official Microsoft documentation不包括这一点。

AuthorizeAttribute class

Specifies that access to a controller or action method is restricted to users who meet the authorization requirement.

Properties:

Roles - Gets or sets the user roles that are authorized to access the controller or action method.

这就是我们所拥有的范围。

打开您的启动文件并将其更改为:

services.AddDefaultIdentity<IdentityUser>()
.AddEntityFrameworkStores<ApplicationDbContext>();

对此:

services.AddIdentity<IdentityUser, IdentityRole>()
                .AddEntityFrameworkStores<ApplicationDbContext>()
                .AddDefaultUI()
                .AddDefaultTokenProviders();

然后角色应该开始工作了。

授权属性,例如User.IsInRole 查看 User.Identity 角色声明。

默认情况下,权限(用户登录的地方)将添加来自 AspNetUserRoles table 的角色作为类型“http://schemas.microsoft.com/ws/2008/06/identity/claims/role”的声明。参见 WIF claimtypes members

客户端应用程序将自动从令牌/cookie 中获取信息并将其转换为 User.Identity。当声明类型匹配时,角色类型声明将映射为角色。

这意味着该应用不需要访问用户存储。在大多数情况下,这也是不可能的。所以它实际上不是关于性能,而是关于可访问性。通常应用程序无权访问身份上下文。所以 UserManager 不是一个选项。

然而,使用声明时有一个缺点。该信息已过时。当用户登录时,声明当时的快照被添加到身份中。如果同时声明(或角色)在数据库中更新,则不会记录这些更改。只有用户重新登录后,修改才会生效。

这意味着声明仅适用于 table 不(经常)更改的信息,除非您找到使声明无效的方法。但这可能意味着访问数据库或调用权限。

这就是我不推荐使用角色的原因。由于角色往往用于授权,但您不能同时撤销访问权限。因此,在您解决该问题之前,您可能需要考虑替代方案。

坚持使用 UserManager 不是替代方案,因为上下文可能不适用于所有应用程序。

这就是为什么基于资源的授权可能是适合您的解决方案。请阅读我的回答 以了解更多想法。