Implement admin-only authorization policy
Adds an authorization policy to restrict access to admin-only endpoints. Creates an `AdminOnlyRequirement` and `AdminOnlyHandler` to check if a user has admin privileges. Applies the "AdminOnly" policy to the AdminController to secure admin functionalities. Modifies the endpoint for changing user admin status to include the user ID in the route.
This commit is contained in:
parent
b2b8d1e076
commit
b59fef222f
4 changed files with 74 additions and 30 deletions
|
@ -1,7 +1,6 @@
|
|||
namespace DrinkRateAPI.ApiModels.UserProfile;
|
||||
|
||||
public class ChangeUserAdminStatusRequest
|
||||
public class ChangeAdminStatusBody
|
||||
{
|
||||
public required string UserId { get; set; }
|
||||
public bool ChangeStatusTo { get; set; }
|
||||
}
|
49
DrinkRateAPI/AuthorizationPolicies/AdminOnlyRequirement.cs
Normal file
49
DrinkRateAPI/AuthorizationPolicies/AdminOnlyRequirement.cs
Normal file
|
@ -0,0 +1,49 @@
|
|||
using DrinkRateAPI.DbEntities;
|
||||
using DrinkRateAPI.Services;
|
||||
|
||||
namespace DrinkRateAPI.AuthorizationPolicies;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
|
||||
public class AdminOnlyRequirement : IAuthorizationRequirement
|
||||
{
|
||||
}
|
||||
|
||||
public class AdminOnlyHandler : AuthorizationHandler<AdminOnlyRequirement>
|
||||
{
|
||||
private readonly ApplicationUserService _applicationUserService;
|
||||
private readonly UserProfileService _userProfileService;
|
||||
|
||||
public AdminOnlyHandler(
|
||||
ApplicationUserService applicationUserService,
|
||||
UserProfileService userProfileService)
|
||||
{
|
||||
_applicationUserService = applicationUserService;
|
||||
_userProfileService = userProfileService;
|
||||
}
|
||||
|
||||
protected override async Task HandleRequirementAsync(
|
||||
AuthorizationHandlerContext context,
|
||||
AdminOnlyRequirement requirement)
|
||||
{
|
||||
DbUserProfile userProfile;
|
||||
|
||||
try
|
||||
{
|
||||
userProfile = await _applicationUserService.UserProfileByApplicationUserAsync(context.User);
|
||||
}
|
||||
catch (Exception _)
|
||||
{
|
||||
context.Fail();
|
||||
return;
|
||||
}
|
||||
|
||||
if (_userProfileService.IsUserProfileAdmin(userProfile))
|
||||
{
|
||||
context.Succeed(requirement);
|
||||
}
|
||||
else
|
||||
{
|
||||
context.Fail();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,38 +1,30 @@
|
|||
using DrinkRateAPI.ApiModels.UserProfile;
|
||||
using DrinkRateAPI.Services;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace DrinkRateAPI.Controllers;
|
||||
|
||||
[ApiController]
|
||||
[Route("admin")]
|
||||
[Authorize(Policy = "AdminOnly")]
|
||||
public class AdminController : ControllerBase
|
||||
{
|
||||
private readonly ILogger<AdminController> _logger;
|
||||
private readonly ApplicationUserService _applicationUserService;
|
||||
private readonly UserProfileService _userProfileService;
|
||||
|
||||
public AdminController(ILogger<AdminController> logger, ApplicationUserService applicationUserService,
|
||||
UserProfileService userProfileService)
|
||||
public AdminController(ILogger<AdminController> logger, UserProfileService userProfileService)
|
||||
{
|
||||
_logger = logger;
|
||||
_applicationUserService = applicationUserService;
|
||||
_userProfileService = userProfileService;
|
||||
}
|
||||
|
||||
[HttpPut]
|
||||
[Route("adminStatus")]
|
||||
[HttpPut("users/{userId}/adminStatus")]
|
||||
[Produces("application/json")]
|
||||
public async Task<IActionResult> PutUserAdminStatus([FromBody] ChangeUserAdminStatusRequest request)
|
||||
public async Task<IActionResult> PutUserAdminStatus(string userId, [FromBody] ChangeAdminStatusBody body)
|
||||
{
|
||||
var userProfile = await _applicationUserService.UserProfileByApplicationUserAsync(User);
|
||||
if (!_userProfileService.IsUserProfileAdmin(userProfile))
|
||||
{
|
||||
return Unauthorized();
|
||||
}
|
||||
var changedProfile = await _userProfileService.ChangeUserAdminStatusAsync(userId, body.ChangeStatusTo);
|
||||
|
||||
var changedProfile = await _userProfileService.ChangeUserAdminStatusAsync(request.UserId, request.ChangeStatusTo);
|
||||
|
||||
return Ok(changedProfile);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,6 +1,8 @@
|
|||
using DrinkRateAPI.AuthorizationPolicies;
|
||||
using DrinkRateAPI.Contexts;
|
||||
using DrinkRateAPI.DbEntities;
|
||||
using DrinkRateAPI.Services;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
using Microsoft.OpenApi.Models;
|
||||
|
||||
|
@ -11,10 +13,13 @@ var builder = WebApplication.CreateBuilder(args);
|
|||
builder.Services.AddControllers();
|
||||
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
|
||||
builder.Services.AddEndpointsApiExplorer();
|
||||
builder.Services.AddAuthorization();
|
||||
builder.Services.AddAuthorizationBuilder()
|
||||
.AddPolicy("AdminOnly", policy =>
|
||||
policy.Requirements.Add(new AdminOnlyRequirement()));
|
||||
builder.Services.AddIdentityApiEndpoints<DbApplicationUser>()
|
||||
.AddEntityFrameworkStores<ApplicationDbContext>();
|
||||
builder.Services.AddScoped<UserManager<DbApplicationUser>, UserWithProfileManager>();
|
||||
builder.Services.AddScoped<IAuthorizationHandler, AdminOnlyHandler>();
|
||||
|
||||
builder.Services.AddSwaggerGen(c =>
|
||||
{
|
||||
|
@ -32,20 +37,19 @@ builder.Services.AddSwaggerGen(c =>
|
|||
|
||||
c.AddSecurityRequirement(new OpenApiSecurityRequirement()
|
||||
{
|
||||
{
|
||||
new OpenApiSecurityScheme
|
||||
{
|
||||
Reference = new OpenApiReference
|
||||
new OpenApiSecurityScheme
|
||||
{
|
||||
Type = ReferenceType.SecurityScheme,
|
||||
Id = "Bearer"
|
||||
Reference = new OpenApiReference
|
||||
{
|
||||
Type = ReferenceType.SecurityScheme,
|
||||
Id = "Bearer"
|
||||
},
|
||||
Scheme = "oauth2",
|
||||
Name = "Bearer",
|
||||
In = ParameterLocation.Header,
|
||||
},
|
||||
Scheme = "oauth2",
|
||||
Name = "Bearer",
|
||||
In = ParameterLocation.Header,
|
||||
|
||||
},
|
||||
new List<string>()
|
||||
new List<string>()
|
||||
}
|
||||
});
|
||||
});
|
||||
|
@ -72,4 +76,4 @@ app.UseAuthorization();
|
|||
|
||||
app.MapControllers();
|
||||
|
||||
app.Run();
|
||||
app.Run();
|
Loading…
Reference in a new issue