角色'permissions'转换角色时留下

Role 'permissions' stay when changing role

我有一个 ASP.NET 核心 MVC 站点,带有 SQLite 数据连接,使用 ASP.NET 核心授权,如下所示:

// Startup.ConfigureServices
services.AddAuthorization(e =>
{
    e.AddPolicy(Policies.UserRead, b => b.RequireRole("Editor", "Root"));
}

这是限制访问包含用户信息的站点的策略之一。 (Policies.UserRead 是常数 string)。然后将此策略应用于这样的视图:

[Authorize(Policies.UserRead)]
public async Task<IActionResult> Index()
{
}

效果很好,只有具有 EditorRoot 角色的用户才能访问该视图。但是当登录时更改用户角色时会出现问题。例如

您会认为用户 A 不能再访问 Index(),因为他不再是角色 Editor。但他仍然可以——只要他不注销并重新登录,因为重新登录可以解决这个问题。似乎有人(我认为 ClaimsPrincipal 是这里的罪魁祸首)缓存了这个角色 - 如果我知道如何使缓存无效,这将是 OK...


角色转换代码:

// get the user whos role is changed
var targetUser = await _context.Users.SingleOrDefaultAsync(m => m.Id == model.Id);
if (targetUser == null) return NotFound();

// get the user who changes the role
var sourceUser = await _userManager.GetUserAsync(User);
if (sourceUser == null) return RedirectToAction("Index");

// remove the current role
await _userManager.RemoveFromRoleAsync(targetUser, targetUser.Role.ToString());

// add to the new role
await _userManager.AddToRoleAsync(targetUser, model.Role.ToString());

// update & save the changes
_context.Update(targetUser);
await _context.SaveChangesAsync();

这基本上是我用来更改用户角色的代码(我删除了 view/model 部分,因为它们不相关)。备注:


我尝试使用 SignInManger<> 重新登录用户,但似乎您只能注销当前用户 - 这将是正在更改角色的用户,而不是角色将被更改的用户。


我错过了什么?如果用户无需执行任何操作(例如重新登录)即可 "refresh" 用户角色,那就太好了。

问题是用户的角色声明存储在 cookie 中(aspnet 身份的默认实现),因此除非用户注销,否则即使用户的角色发生变化,授权结果也不会改变。解决方案是使用 ValidateAsync 事件。 Example 存在于官方文档中。

另一种可能的解决方案是从 cookie 中排除角色声明并使用声明转换。

为此,您需要覆盖 UserClaimsPrincipalFactoryCreateAsync 方法,请参阅此 article how to change claims. Then you can use claims transformation 添加角色声明。