在ASP.NET 5
中,假设我有以下控制器:
[Route("api/[controller]")]
[Authorize(Roles = "Super")]
public class ValuesController : Controller
{
// GET: api/values
[HttpGet]
public IEnumerable<string> Get()
{
return new[] { "value1", "value2" };
}
}
然后假设我有一个用户Jack,他已登录但不是 Super 角色的成员。
当Jack试图访问此资源时,他会按预期拒绝访问。
然后,从另一台机器,我使用UserManager将他添加到 Super 角色。
当Jack再次尝试访问此资源时,它仍会被拒绝访问,直到他退出并重新登录。
如何确保每个用户的角色未缓存,或者在进行更改时以某种方式刷新?
答案 0 :(得分:1)
所以这就是我最终如何设法解决这个问题,但实际上这应该用安全标记来解决。下面的解决方案至少在授权发生之前提供“查看”。
我创建了一个新的AuthorizationHandler
,在其构造函数中接受UserManager
:
public class SuperRequirement : AuthorizationHandler<SuperRequirement>, IAuthorizationRequirement
{
public UserManager<ApplicationUser> UserManager { get; set; }
public SuperRequirement(UserManager<ApplicationUser> userManager)
{
UserManager = userManager;
}
protected override void Handle(AuthorizationContext context, SuperRequirement requirement)
{
throw new System.NotImplementedException();
}
protected override async Task HandleAsync(AuthorizationContext context, SuperRequirement requirement)
{
var userName = context.User.Identity.Name;
var pass = await UserManager.IsInRoleAsync(await UserManager.FindByNameAsync(userName), "Super");
if (pass)
{
context.Succeed(requirement);
}
else
{
context.Fail();
}
}
}
然后我在Startup.cs
:
public void ConfigureServices(IServiceCollection services)
{
...
var sp = services.BuildServiceProvider();
//var service = sp.GetService<ISomeService>();
services.AddAuthorization(options =>
{
options.AddPolicy("Super",
policy =>
{
var userManager = sp.GetService<UserManager<ApplicationUser>>();
policy.Requirements.Add(new SuperRequirement(userManager));
});
});
}
最后我更新了我的控制器以使用新的授权策略:
[Route("api/[controller]")]
[Authorize(Policy = "Super")]
public class ValuesController : Controller
{
// GET: api/values
[HttpGet]
public IEnumerable<string> Get()
{
return new[] { "value1", "value2" };
}
}
这样,它会检查每个请求的数据库,以确保角色对齐,使用UserManager
执行此操作。
请注意这效率较低,因为每个API请求现在都会触发对数据库的额外调用,因此您应该实现某种缓存和失效机制;这只是为了证明这一原则。