【问题标题】:Asp.net core web-api http action based authorizationAsp.net core web-api http 基于动作的授权
【发布时间】:2021-04-26 12:52:49
【问题描述】:

我正在尝试向 asp.net core api 添加两个策略。

  1. 只读 - 只允许获取调用
  2. AppUser - 允许获取、放置、发布、删除

//// 政策在 appsettings json 中

Policies.json
{
    "name": "ReadOnly"
    "ids":["user1", "user2"],
}
,
{
    "name": "AppUser"
    "ids":["user3", "user4"]
}

//// 要求

public class IdRequirement : IAuthorizationRequirement
{
    public string Name { get; set; }
    public List<string> Ids { get; set; } = new List<string>();

    public IdRequirement(string name, List<string> ids)
    {
        Name = name;
        Ids = ids;
    }
}

//// 处理程序

public class IdHandler : AuthorizationHandler<IdRequirement>
{
    protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, IdRequirement requirement)
    {
        if (context.User.Identity.IsAuthenticated) 
        {
            string currentUserid = GetId(context.User);

            if (requirement.Ids != null && requirement.Ids.Any(x => x == currentUserid))
            {
                context.Succeed(requirement);
            }
        }

        return Task.CompletedTask;
    }
}

//// 在服务中

services.AddAuthorization(options =>
{
    var reqList = configuration.GetSection("Policies").Get<List<IdRequirement>>();

    //// app users must have readonly access by default. ReadOnly is the default policy.
    //// not sure this is the correct way?
    
    var appUserReq = reqList.Find(x => x.Name.Equals("AppUser", StringComparison.Ordinal));
    var readOnlyReq = reqList.Find(x => x.Name.Equals("ReadOnly", StringComparison.Ordinal));

    readOnlyReq.Ids = readOnlyReq.Ids.Union(appUserReq.ids).ToList();

    reqList.ForEach(requirement =>
    {
        options.AddPolicy(requirement.Name, policy =>
        {
            policy.AddAuthenticationSchemes(JwtBearerDefaults.AuthenticationScheme);
            policy.Requirements.Add(requirement);

        });
    });
});

//// 在配置中

app.UseEndpoints(endpoints =>
{
    endpoints.MapControllers().RequireAuthorization("ReadOnly");
});

//// 控制器

public class TestController : BaseController
{
    // GET: userid
    [HttpGet("testget")]
    public async Task<IActionResult> GetSomething()
    {
        return Ok();
    }

    [Authorize(Policy = "AppUser")]
    [HttpPost("testpost")]
    public async Task<IActionResult> PostSomething()
    {
        return Ok();
    }
}

如果我调用 testget,它只会授权只读要求。这对我来说是正确的。

如果我调用 testpost,它会先授权 appuser 需求,然后再调用 readonly 需求。

我不想在使用 [Authorize(Policy = "AppUser")] 时触发只读要求

  1. 是我遗漏了这里还是误用了概念?
  2. 这是默认行为吗?

我参考了这篇文章 https://github.com/blowdart/AspNetAuthorizationWorkshop

【问题讨论】:

    标签: asp.net-core authorization asp.net-core-webapi asp.net-authorization


    【解决方案1】:

    最后使用post 的帮助,我实现了如下所示。确保您不再需要在控制器中添加 Authorize 属性。如果您想要特定控制器的任何自定义设置,可以修改RequireAuthorizationForHttpMethods

    var mutatingHttpMethods = new HashSet<HttpMethod>()
    {
        HttpMethod.Post,
        HttpMethod.Put,
        HttpMethod.Delete
    };
    
    var getHttpMethods = new HashSet<HttpMethod>()
    {
        HttpMethod.Get
    };
    
    endpoints
        .MapControllers()
        .RequireAuthorizationForHttpMethods(httpMethods => httpMethods.Any(httpMethod => getHttpMethods.Contains(httpMethod)), "ReadOnly")
        .RequireAuthorizationForHttpMethods(httpMethods => httpMethods.Any(httpMethod => mutatingHttpMethods.Contains(httpMethod)), "AppUser");
    

    【讨论】:

      【解决方案2】:

      你没有错过任何东西。将[Authorize(Policy = "AppUser")] 放在操作上时,它将首先通过此策略AppUser 进行身份验证。如果不成功,它将重定向到AccessDeniedPath。这时候会经过端点,RequireAuthorization作为端点中的全局授权会再次被触发。如果不配置AccessDeniedPath,会返回404。

      【讨论】:

      • 我的问题是即使 AppUser 策略成功,之后也触发了只读要求。我的意思是不需要这样做吗?
      • 是的,它会先验证 AppUser,然后验证 ReadOnly。
      • 所以即使先前的策略成功调用另一个策略也不是开销?
      • 不,这个开销很小,不会显着影响运行效率
      猜你喜欢
      • 2021-03-12
      • 2020-05-19
      • 2019-05-27
      • 2018-03-01
      • 1970-01-01
      • 2023-03-12
      • 2020-11-16
      • 2012-12-22
      • 2020-05-18
      相关资源
      最近更新 更多