微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

Asp.net core web-api 基于http动作的授权

如何解决Asp.net core web-api 基于http动作的授权

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

  1. ReadOnly - 只允许 get 调用
  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

解决方法

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

,

最后使用来自此 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");

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。