Reputation: 1364
Because of the API is shared with admin and user. So I want to check the policy inside the action if the user id not equal with the parameter.
To simplify, this application using jwt token as the access token. So as for now have 2 roles which it User
and Admin
. So I add policy based on claims for this roles. Here how I generate the policy in startup.cs
public static IServiceCollection AddCustomAuthorizationPolicy(this IServiceCollection services)
{
services.AddAuthorization(options = >options.AddPolicy("UserOnly", policy = >policy.RequireClaim(CustomClaimTypes.UserManagement, "User", "Admin")));
services.AddAuthorization(options = >options.AddPolicy("RequireAdmin", policy = >policy.RequireClaim(CustomClaimTypes.UserManagement, "Admin")));
return services;
}
UserOnly
allow both of roles. RequireAdmin
for admin only.
Here is the current API I do for change the password
[HttpPost("{id}/change-password")]
[Authorize(Policy = "RequireAdmin")]
public async Task <IActionResult> ChangePassword([FromRoute] string id, [FromBody] UserChangePasswordViewModel model)
{
//This authorize filter require admin.
//But I also want allow user to access
var user = await _userManager.FindByIdAsync(id);
if (user == null) return BadRequest("User not found");
//My business logic here
}
So I change to UserOnly
which allow both of roles to access it
[HttpPost("{id}/change-password")]
[Authorize(Policy = "UserOnly")]
public async Task < IActionResult > ChangePassword([FromRoute] string id, [FromBody] UserChangePasswordViewModel model)
{
var getCurrentUserId = _identityService.GetUserIdentity();
var user = await _userManager.FindByIdAsync(id);
if (user == null) return BadRequest("User not found");
if(getCurrentUserId != id)
{
//Check if this user is admin
if(!isAdmin) //<-- Here I want to check the policy
{
//Response 403 forbidden
}
}
//My business logic here
}
But I not really sure how to check policy inside the action. Any better suggestion? or need to use HttpContext.User
for find the claim and check the value?
Upvotes: 4
Views: 4464
Reputation: 2905
You can make a dynamic policy decision by taking a dependency in your controller on IAuthorizationService
and calling the IAuthorizationService.AuthorizeAsync
method. An example of some fictional controller:
private readonly IAuthorizationService _authorizationService;
public MyController(IAuthorizationService authorizationService)
{
_authorizationService = authorizationService;
}
[HttpPost("{id}/protected-action")]
public async Task <IActionResult> SomeDynamicallyProtectedAction()
{
var isAdminEvaluationResult =
await _authorizationService.AuthorizeAsync(User, null, "RequireAdmin");
if (!isAdminEvaluationResult.Succeeded)
{
return Forbid();
}
// ...continue processing the request
}
Upvotes: 5
Reputation: 28352
In my opinion, there is no need to call RequireAdmin policy again in the action method to check the user is admin or not.
You could directly get the CustomClaimTypes.UserManagement claim value from User
in the action method. Then you could write some logic to check the user is admin or not.
More details about how to get the CustomClaimTypes.UserManagement claim value and check it ,you could refer to below codes:
public async Task<IActionResult> Get()
{
string role = User.Claims.FirstOrDefault(x => x.Type == CustomClaimTypes.UserManagement).Value;
if (role != "Admin")
{
return Forbid();
}
return Ok(new string[] { "value1", "value2" });
}
Result:
Upvotes: 2