User profile service #2

Merged
Jiri merged 16 commits from 250809_UserProfile into main 2025-08-11 20:10:50 +00:00
4 changed files with 74 additions and 30 deletions
Showing only changes of commit b59fef222f - Show all commits

View file

@ -1,7 +1,6 @@
namespace DrinkRateAPI.ApiModels.UserProfile; namespace DrinkRateAPI.ApiModels.UserProfile;
public class ChangeUserAdminStatusRequest public class ChangeAdminStatusBody
{ {
public required string UserId { get; set; }
public bool ChangeStatusTo { get; set; } public bool ChangeStatusTo { get; set; }
} }

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

View file

@ -1,38 +1,30 @@
using DrinkRateAPI.ApiModels.UserProfile; using DrinkRateAPI.ApiModels.UserProfile;
using DrinkRateAPI.Services; using DrinkRateAPI.Services;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
namespace DrinkRateAPI.Controllers; namespace DrinkRateAPI.Controllers;
[ApiController] [ApiController]
[Route("admin")] [Route("admin")]
[Authorize(Policy = "AdminOnly")]
public class AdminController : ControllerBase public class AdminController : ControllerBase
{ {
private readonly ILogger<AdminController> _logger; private readonly ILogger<AdminController> _logger;
private readonly ApplicationUserService _applicationUserService;
private readonly UserProfileService _userProfileService; private readonly UserProfileService _userProfileService;
public AdminController(ILogger<AdminController> logger, ApplicationUserService applicationUserService, public AdminController(ILogger<AdminController> logger, UserProfileService userProfileService)
UserProfileService userProfileService)
{ {
_logger = logger; _logger = logger;
_applicationUserService = applicationUserService;
_userProfileService = userProfileService; _userProfileService = userProfileService;
} }
[HttpPut] [HttpPut("users/{userId}/adminStatus")]
[Route("adminStatus")]
[Produces("application/json")] [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); var changedProfile = await _userProfileService.ChangeUserAdminStatusAsync(userId, body.ChangeStatusTo);
if (!_userProfileService.IsUserProfileAdmin(userProfile))
{
return Unauthorized();
}
var changedProfile = await _userProfileService.ChangeUserAdminStatusAsync(request.UserId, request.ChangeStatusTo);
return Ok(changedProfile); return Ok(changedProfile);
} }
} }

View file

@ -1,6 +1,8 @@
using DrinkRateAPI.AuthorizationPolicies;
using DrinkRateAPI.Contexts; using DrinkRateAPI.Contexts;
using DrinkRateAPI.DbEntities; using DrinkRateAPI.DbEntities;
using DrinkRateAPI.Services; using DrinkRateAPI.Services;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Identity; using Microsoft.AspNetCore.Identity;
using Microsoft.OpenApi.Models; using Microsoft.OpenApi.Models;
@ -11,10 +13,13 @@ var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllers(); builder.Services.AddControllers();
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle // Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer(); builder.Services.AddEndpointsApiExplorer();
builder.Services.AddAuthorization(); builder.Services.AddAuthorizationBuilder()
.AddPolicy("AdminOnly", policy =>
policy.Requirements.Add(new AdminOnlyRequirement()));
builder.Services.AddIdentityApiEndpoints<DbApplicationUser>() builder.Services.AddIdentityApiEndpoints<DbApplicationUser>()
.AddEntityFrameworkStores<ApplicationDbContext>(); .AddEntityFrameworkStores<ApplicationDbContext>();
builder.Services.AddScoped<UserManager<DbApplicationUser>, UserWithProfileManager>(); builder.Services.AddScoped<UserManager<DbApplicationUser>, UserWithProfileManager>();
builder.Services.AddScoped<IAuthorizationHandler, AdminOnlyHandler>();
builder.Services.AddSwaggerGen(c => builder.Services.AddSwaggerGen(c =>
{ {
@ -32,20 +37,19 @@ builder.Services.AddSwaggerGen(c =>
c.AddSecurityRequirement(new OpenApiSecurityRequirement() c.AddSecurityRequirement(new OpenApiSecurityRequirement()
{ {
{
new OpenApiSecurityScheme
{ {
Reference = new OpenApiReference new OpenApiSecurityScheme
{ {
Type = ReferenceType.SecurityScheme, Reference = new OpenApiReference
Id = "Bearer" {
Type = ReferenceType.SecurityScheme,
Id = "Bearer"
},
Scheme = "oauth2",
Name = "Bearer",
In = ParameterLocation.Header,
}, },
Scheme = "oauth2", new List<string>()
Name = "Bearer",
In = ParameterLocation.Header,
},
new List<string>()
} }
}); });
}); });
@ -72,4 +76,4 @@ app.UseAuthorization();
app.MapControllers(); app.MapControllers();
app.Run(); app.Run();