.NET核心授权,具有自定义要求/处理程序



我之前和其他人都问了类似的问题,我取得了一些进展,但仍然不确定我在这里做错了或错过了什么。

我的应用程序很简单:域用户被认证。身份验证的用户(作者)创建一个请求,保存在数据库中。其他身份验证的用户只能查看请求。作者和管理用户可以编辑/删除请求。

这是我遵循的示例之一:不同角色的不同API功能

和另一个策略:我不确定如何在此处使用/注册/调用许可者。

这是我的代码:

startup.cs

//  Add Authentication
//  Global filter
services.AddMvc(config =>
{
    var policy = new AuthorizationPolicyBuilder()
                     .RequireAuthenticatedUser()
                     .RequireRole("Role - Domain Users")
                     .Build();
    config.Filters.Add(new AuthorizeFilter(policy));
});

//  Add Authorization Handlers
services.AddAuthorization(options =>
{
    options.AddPolicy("EditPolicy", policy => policy.Requirements.Add(new EditRequirement()));
});
services.AddSingleton<IAuthorizationHandler, PermissionHandler>();

editrequirement.cs

public class EditRequirement : IAuthorizationRequirement
{
}

curmissionler.cs

public class PermissionHandler : IAuthorizationHandler
{
    public Task HandleAsync(AuthorizationHandlerContext context)
    {
        var pendingRequirements = context.PendingRequirements.ToList();
        foreach (var requirement in pendingRequirements)
        {
            if (requirement is ReadRequirement)
            {
                if (IsOwner(context.User, context.Resource) ||
                    IsAdmin(context.User, context.Resource))
                {
                    context.Succeed(requirement);
                }
            }
            else if (requirement is EditRequirement ||
                     requirement is DeleteRequirement)
            {
                if (IsOwner(context.User, context.Resource) || IsAdmin(context.User, context.Resource))
                {
                    context.Succeed(requirement);
                }
            }
        }
        return Task.CompletedTask;
    }
    private bool IsAdmin(ClaimsPrincipal user, object resource)
    {
        if (user.IsInRole("Role - Administrator"))
        {
            return true;
        }
        return false;
    }
    private bool IsOwner(ClaimsPrincipal user, object resource)
    {
        if (resource is CreateRequestViewModel)
        {
            var ctx = (CreateRequestViewModel)resource;
            if (ctx.RequestEnteredBy.Equals(user.Identity.Name))
            {
                return true;
            }
        }
        else if (resource is AuthorizationFilterContext)
        {
            var afc = (AuthorizationFilterContext)resource;
            //  This is not right, but I don't know how to deal with AuthorizationFilterContext 
            //  type passed into resource parameter when I click Edit button trying to edit the request
            if (afc.HttpContext.User.Identity.Name.Equals(user.Identity.Name))
            {
                return true;
            }
        }
        else if (resource is Request)
        {
            var r = (Request)resource;
            if (r.RequestEnteredBy.Equals(user.Identity.Name))
            {
                return true;
            }
        }

        return false;
    }
    private bool IsSponsor(ClaimsPrincipal user, object resource)
    {
        // Code omitted for brevity
        return true;
    }
}

requestscontroller.cs

private IAuthorizationService _authorizationService;
public RequestsController(ApplicationModelContext context, IAuthorizationService authorizationService)
{
    _context = context; 
    _authorizationService = authorizationService;
}
[Authorize(Policy = "EditPolicy")]
public async Task<IActionResult> Edit(int? id)
{
    if (id == null)
    {
        return NotFound();
    }
    CreateRequestViewModel crvm = new CreateRequestViewModel();
    var request = await _context.Request
                .SingleOrDefaultAsync(m => m.RequestId == id);
    if (request == null)
    {
        return NotFound();
    }
    var authorizationResult = await _authorizationService.AuthorizeAsync(User, request, "EditPolicy");
    if (authorizationResult.Succeeded)
    {   
        //  Load request contents and return to the view
        return View(crvm);
    }
    //  This needs to be changed to redirect to a message screen saying no permission
    return RedirectToAction("Details", new { id = request.RequestId });
}

当我调试应用程序时,我发现:

  • 页面第一次从数据库加载请求时,它通过createrequestViewModel类型的对象,用于资源参数许可中的ISONDER方法。
  • 单击页面请求项目的编辑按钮后,它通过授权FilterContext类型
  • 然后进入ReuqestController中的编辑操作,该操作发送了请求类型(在_authorizationservice.authorizeasync中)。

不确定我是否做了重复或与不同方法完全混合的事情。

任何建议都将不胜感激。

看起来您正在混合策略和基于资源的授权。基于资源的声音就像您想要的那样,因为您可能不想为每个CRUD操作创建策略,即" CreateUserPolicy"," UpdateUserPolicy",然后将不同的要求传递给每个要求。请参阅本基于资源授权的教程:https://lealen.microsoft.com/en-us/aspnet/core/core/security/authorization/resourcebased?view=aspnetcore-2.2

为了授权使用用户资源,我创建了一个Userauthorizationhandler:

startup.cs:

services.AddScoped<IAuthorizationHandler, UserAuthorizationHandler>();

userauthorizationhandler.cs

public class UserAuthorizationHandler : AuthorizationHandler<OperationAuthorizationRequirement, User>
{
    private readonly IPermissionRepository _permissionRepository;
    public UserAuthorizationHandler(IPermissionRepository permissionRepository)
    {
        _permissionRepository = permissionRepository;
    }
    protected override async Task HandleRequirementAsync(AuthorizationHandlerContext context, OperationAuthorizationRequirement requirement, User resource)
    {
        var authUserId = int.Parse(context.User.FindFirstValue(ClaimTypes.NameIdentifier));
        if (requirement == AuthorizationOperations.Create)
        {
            if (await CanCreate(authUserId))
            {
                context.Succeed(requirement);
            }
        }
        else if (requirement == AuthorizationOperations.Read)
        {
            if (await CanRead(authUserId, resource))
            {
                context.Succeed(requirement);
            }
        }
    }
    /// <summary>
    /// User can create if they have 'create' 'users' permission.
    /// </summary>
    /// <param name="authUserId">The requesting user</param>
    /// <returns></returns>
    public async Task<bool> CanCreate(int authUserId)
    {
        return await _permissionRepository.UserHasPermission(authUserId, "create", "users");
    }
    /// <summary>
    /// User can read if reading themselves or they have the 'read' 'users' permission.
    /// </summary>
    /// <param name="authUserId">The requesting user</param>
    /// <param name="user">The requested resource</param>
    /// <returns></returns>
    public async Task<bool> CanRead(int authUserId, User user)
    {
        return authUserId == user.Id || await _permissionRepository.UserHasPermission(authUserId, "read", "users");
    }
}

控制器:

  var authorized = await _authorizationService.AuthorizeAsync(User, new User { Id = id}, AuthorizationOperations.Read);
  if (!authorized.Succeeded)
  {
    return Unauthorized();
  }

最新更新