目前 middleware 中的代码是这么写的
public class AuthorizeMiddleware
{
private RequestDelegate _next;
public AuthorizeMiddleware(RequestDelegate next)
{
_next = next;
}
public async Task Invoke(HttpContext context, IUserService userService)
{
var identity = context.User.Identity;
if (identity.IsAuthenticated
&& await userService.IsUserInRole(ROLE_NAME, identity.Name))
{
context.User.AddIdentity(new ClaimsIdentity("Basic", ClaimTypes.Role, ROLE_NAME));
}
await _next(context);
}
}
在 Authorization Policy 中使用这个角色进行授权,但不起作用
services.AddMvc(o =>
{
var policy = new AuthorizationPolicyBuilder()
.RequireRole(ROLE_NAME)
.Build();
o.Filters.Add(new AuthorizeFilter(policy));
});
请问如何解决这个问题?
通过查看 HttpAbstractions 与 Security 的源代码,知道了这个问题实际上就是如何给已有 ClaimsPrincipal (HttpContext.User) 添加 Claim
自己解决了。之前使用 AddIdentity
是不正确的方法,需要在已有的 context.User.Identity
中添加 Claim ,但 context.User.Identity
的类型是 IIdentity ,它没有提供添加 Claim 的方法。
后来在 stackoverflow 的 Update claims in ClaimsPrincipal 中知道了可以将 context.User.Identity
转换为 ClaimsIdentity
,通过它就可以添加 Claim 了。
var claimsIdentity = context.User.Identity as ClaimsIdentity;
if(claimsIdentity != null)
{
claimsIdentity.AddClaim(new Claim(ClaimTypes.Role, ROLE_NAME));
}
为什么不在登陆的时候添加role,而在中间件里动态添加role?中间件里不用判断当前访问的页面吗?
@大豆男生: 是登录时添加role更好,这里是特殊场景所致——暂时不能修改登录部分的代码。整个应用只允许授权角色才能访问
@dudu: 学习了,感觉微软的这套设计得很复杂,还真不容易上手。
我都是加一个前置中间件,把token(or cookie)转换为userinfo,存储到Context.Items中的,然后在授权filter中检查用户权限。
我想充分利用 asp.net core 的 authorization 机制
这个方法在权限变动频繁时候太麻烦了, 所有token中除了用于不会变的东西, 我一般啥也不存储
用 AuthorizationFilter 应该比 Middleware 方便些吧
public class UserAuthorizeFilter : IAuthorizationFilter { public void OnAuthorization(AuthorizationFilterContext context) {
所有的Middleware都在app.UseMvc之前执行。所以AuthorizationFilter比Middleware能获取更多信息,包括 Controller,Action 名称等。