Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
264 views
in Technique[技术] by (71.8m points)

Asp.net core web-api http action based authorization

I am trying to add two policies to asp.net core api.

  1. ReadOnly - only allow get calls
  2. AppUser - allow get,put,post,delete

//// policies are in appsettings json

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

//// requirement

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;
    }
}

//// handler

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;
    }
}

//// in services

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);

        });
    });
});

//// in configure

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

//// controller

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();
    }
}

If I call testget, it will only authorize readonly requirement. Which is correct for me.

If I call testpost, it will first authorize appuser requirement, then again call readonly requirement.

I don't want to trigger readonly requirement when using [Authorize(Policy = "AppUser")]

  1. Am I missing here or misuse concept?
  2. Is this default behavior?

I referred this article https://github.com/blowdart/AspNetAuthorizationWorkshop

question from:https://stackoverflow.com/questions/65838659/asp-net-core-web-api-http-action-based-authorization

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

You are not missing anything. When putting [Authorize(Policy = "AppUser")] on an action, it will authenticate through this policy AppUser first. If not succeed, it will redirect to AccessDeniedPath. At this time, it will go through the endpoint, and RequireAuthorization as a global authorization in the endpoint will be triggered again. If you do not configure the AccessDeniedPath, it will return 404.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

2.1m questions

2.1m answers

60 comments

57.0k users

...