首页 > 解决方案 > 我可以创建一个自定义授权策略,我可以传递从我的控制器方法接收到的字段吗?

问题描述

我想让我在控制器中从客户端收到的参数用于授权我在我的项目中使用的“POST”方法(用户只能编辑他们分配给的项目)。UserIds 将存在于项目中,因此我需要获取项目并验证当前用户 ID 是否在项目中。

// I want to modify my policy below where I can use "projectId". ProjectId is dynamic and passed in from a ajax call
[Authorize(Policy = "CanModifyProject")]
[HttpPost]
public async Task<IActionResult> SaveWorker(var projectId, workerModel worker)
{
// Code here....
}

我的政策

protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, CanModifyProject requirement)
        {
            bool isSuperAdmin = context.User.IsAdmin();
            bool isAdmin = context.User.IsAdmin();
            var currentUserId = context.User.GetUserId();

            // I NEED TO HAVE THE DYNAMIC PROJECT ID here recieved by "POST" methods
            int projectId = 0;

            // Check to see if the project has the assigned User
            var projectUserIsAssigned = this.projectRepository.ProjectIsAssignedToUser(projectId currentUserId);

            if (isSuperAdmin || isAdmin && projectUserIsAssigned)
            {
                context.Succeed(requirement);
                return Task.CompletedTask;
            }
            else
            {
                context.Fail();
                return Task.CompletedTask;
            }
        }

如何在我的 post 方法中访问我的 ProjectId ???

标签: asp.netasp.net-mvcasp.net-coreasp.net-web-api

解决方案


授权阶段在请求处理管道中相当早,在执行操作之前。所以还没有绑定视图模型(通过模型绑定)。为此,我会使用IActionFilteror 。IAsyncActionFilter在那里您可以访问ActionExecutingContext.ActionArguments以获取您想要的自定义授权的绑定参数。

在这里,我想尝试使用通常在IAuthorizationFilteror范围内执行的代码以您想要的方式解决它IAsyncAuthorizationFilter(在AuthorizationMiddleware. 使用这种方法,获取动作参数值的方式受到限制。它应该可以通过一些键清楚地访问,我们得到的原始值当然是一个字符串。根据您的具体要求,它只是一个参数int,可以通过客户端的表单数据或查询字符串发送。

这里的重点是我们可以使用CompositeValueProvider. 代码应该说明一切:

//inject IOptions<MvcOptions> into your CanModifyProject requirement class
//name it as _mvcOptions

protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, CanModifyProject requirement) {
        bool isSuperAdmin = context.User.IsAdmin();
        bool isAdmin = context.User.IsAdmin();
        var currentUserId = context.User.GetUserId();

        var projectId = 0;
        //get projectId
        if(context.Resource is ActionContext ac && 
           ac.ActionDescriptor is ControllerActionDescriptor ca)
        {
            //match only the related controller method
            if(ca.ControllerTypeInfo == typeof(YourController) && 
               ca.MethodInfo.Name == nameof(YourController.SaveWorker)) {

                //create the composite value provider
                var valueProvider = await CompositeValueProvider.CreateAsync(ac, _mvcOptions.Value.ValueProviderFactories);

                //get the raw id (as string)
                var id = valueProvider.GetValue("projectId").FirstValue ?? "";
                //parse your projectId here
                int.TryParse(id, out projectId);
            }                  
        } 

        //your remaining code (unchanged)
        //...
}

推荐阅读