自定义授权的拦截和处理 - 图1

    • 一个管理员用户可以编辑或删除其他管理员用户的角色,但不能编辑或删除自己的角色
    • Func 委托无法满足的情况:
      • 我们无法访问 url 中的查询字符串参数
      • 你可能需要通过使用依赖注入的方式来访问其他服务

    CanEditOnlyOtherAdminRolesAndClaimsHandler:

    1. public class CanEditOnlyOtherAdminRolesAndClaimsHandler : AuthorizationHandler<ManageAdminRolesAndClaimsRequirement>
    2. {
    3. private readonly IHttpContextAccessor _httpContextAccessor;
    4. public CanEditOnlyOtherAdminRolesAndClaimsHandler(IHttpContextAccessor httpContextAccessor)
    5. {
    6. _httpContextAccessor = httpContextAccessor;
    7. }
    8. protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, ManageAdminRolesAndClaimsRequirement requirement)
    9. {
    10. // 获取 httpContext 上下文
    11. var httpContext = _httpContextAccessor.HttpContext;
    12. var loggedInAdminId = context.User.Claims.FirstOrDefault(c => c.Type == ClaimTypes.NameIdentifier).Value;
    13. string adminIdBeingEdited = _httpContextAccessor.HttpContext.Request.Query["userId"];
    14. // 判断用户是 Admin,并且拥有 claim.Type == "Edit Role" 且值为 true
    15. if (context.User.IsInRole("Admin") &&
    16. context.User.HasClaim(claim => claim.Type == "Edit Role" && claim.Value == "true"))
    17. {
    18. // 如果当前拥有 Admin 角色的 userId 为空,说明进入的是角色列表页面。无法判断当前登录用户的 Id
    19. if (string.IsNullOrEmpty(adminIdBeingEdited))
    20. {
    21. context.Succeed(requirement);
    22. }
    23. else if (adminIdBeingEdited.ToLower() != loggedInAdminId.ToLower())
    24. {
    25. // 成功满足需求
    26. context.Succeed(requirement);
    27. }
    28. }
    29. return Task.CompletedTask;
    30. }
    31. }

    Startup 中进行配置:

    1. // 使用声明式授权
    2. services.AddAuthorization(options =>
    3. {
    4. ...
    5. options.AddPolicy("EditRolePolicy", policy => policy.AddRequirements(new ManageAdminRolesAndClaimsRequirement()));
    6. options.InvokeHandlersAfterFailure = false;
    7. });
    8. services.AddSingleton<IAuthorizationHandler, CanEditOnlyOtherAdminRolesAndClaimsHandler>();

    注:为了达到视频中演示的效果,还得给 AdminController 的 ManageUserRoles 也进行权限控制。

    1. [Authorize(Policy = "EditRolePolicy")]
    2. [HttpGet]
    3. public async Task<IActionResult> ManageUserRoles(string userId)
    4. {
    5. ...
    6. }