diff --git a/DrinkRateAPI/ApiModels/UserProfile/ChangeUserAdminStatusRequest.cs b/DrinkRateAPI/ApiModels/UserProfile/ChangeAdminStatusBody.cs similarity index 51% rename from DrinkRateAPI/ApiModels/UserProfile/ChangeUserAdminStatusRequest.cs rename to DrinkRateAPI/ApiModels/UserProfile/ChangeAdminStatusBody.cs index e28228d..238546f 100644 --- a/DrinkRateAPI/ApiModels/UserProfile/ChangeUserAdminStatusRequest.cs +++ b/DrinkRateAPI/ApiModels/UserProfile/ChangeAdminStatusBody.cs @@ -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; } } \ No newline at end of file diff --git a/DrinkRateAPI/AuthorizationPolicies/AdminOnlyRequirement.cs b/DrinkRateAPI/AuthorizationPolicies/AdminOnlyRequirement.cs new file mode 100644 index 0000000..e972e3b --- /dev/null +++ b/DrinkRateAPI/AuthorizationPolicies/AdminOnlyRequirement.cs @@ -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 +{ + 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(); + } + } +} \ No newline at end of file diff --git a/DrinkRateAPI/Controllers/AdminController.cs b/DrinkRateAPI/Controllers/AdminController.cs index 59223f5..4bbc46d 100644 --- a/DrinkRateAPI/Controllers/AdminController.cs +++ b/DrinkRateAPI/Controllers/AdminController.cs @@ -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 _logger; - private readonly ApplicationUserService _applicationUserService; private readonly UserProfileService _userProfileService; - public AdminController(ILogger logger, ApplicationUserService applicationUserService, - UserProfileService userProfileService) + public AdminController(ILogger logger, UserProfileService userProfileService) { _logger = logger; - _applicationUserService = applicationUserService; _userProfileService = userProfileService; } - [HttpPut] - [Route("adminStatus")] + [HttpPut("users/{userId}/adminStatus")] [Produces("application/json")] - public async Task PutUserAdminStatus([FromBody] ChangeUserAdminStatusRequest request) + public async Task 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); } -} +} \ No newline at end of file diff --git a/DrinkRateAPI/Program.cs b/DrinkRateAPI/Program.cs index acdcb89..051ce01 100644 --- a/DrinkRateAPI/Program.cs +++ b/DrinkRateAPI/Program.cs @@ -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() .AddEntityFrameworkStores(); builder.Services.AddScoped, UserWithProfileManager>(); +builder.Services.AddScoped(); 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() + new List() } }); }); @@ -72,4 +76,4 @@ app.UseAuthorization(); app.MapControllers(); -app.Run(); +app.Run(); \ No newline at end of file