I am trying to add two policies to asp.net core api.
- ReadOnly - only allow get calls
- 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")]
- Am I missing here or misuse concept?
- 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 与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…