mirror of
https://github.com/alex289/CleanArchitecture.git
synced 2025-08-23 03:38:36 +00:00
Add User auth
This commit is contained in:
parent
74d546f6c7
commit
b36aaff112
@ -3,9 +3,11 @@
|
|||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net7.0</TargetFramework>
|
<TargetFramework>net7.0</TargetFramework>
|
||||||
<Nullable>enable</Nullable>
|
<Nullable>enable</Nullable>
|
||||||
|
<UserSecretsId>64377c40-44d6-4989-9662-5d778f8b3b92</UserSecretsId>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="7.0.4" />
|
||||||
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="7.0.4" />
|
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="7.0.4" />
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Proxies" Version="7.0.4" />
|
<PackageReference Include="Microsoft.EntityFrameworkCore.Proxies" Version="7.0.4" />
|
||||||
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.5.0" />
|
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.5.0" />
|
||||||
|
@ -4,6 +4,7 @@ using CleanArchitecture.Application.Interfaces;
|
|||||||
using CleanArchitecture.Application.ViewModels.Users;
|
using CleanArchitecture.Application.ViewModels.Users;
|
||||||
using CleanArchitecture.Domain.Notifications;
|
using CleanArchitecture.Domain.Notifications;
|
||||||
using MediatR;
|
using MediatR;
|
||||||
|
using Microsoft.AspNetCore.Authorization;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
|
||||||
namespace CleanArchitecture.Api.Controllers;
|
namespace CleanArchitecture.Api.Controllers;
|
||||||
@ -21,13 +22,15 @@ public class UserController : ApiController
|
|||||||
_userService = userService;
|
_userService = userService;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Authorize]
|
||||||
[HttpGet]
|
[HttpGet]
|
||||||
public async Task<IActionResult> GetAllUsersAsync()
|
public async Task<IActionResult> GetAllUsersAsync()
|
||||||
{
|
{
|
||||||
var users = await _userService.GetAllUsersAsync();
|
var users = await _userService.GetAllUsersAsync();
|
||||||
return Response(users);
|
return Response(users);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Authorize]
|
||||||
[HttpGet("{id}")]
|
[HttpGet("{id}")]
|
||||||
public async Task<IActionResult> GetUserByIdAsync(
|
public async Task<IActionResult> GetUserByIdAsync(
|
||||||
[FromRoute] Guid id,
|
[FromRoute] Guid id,
|
||||||
@ -43,14 +46,16 @@ public class UserController : ApiController
|
|||||||
var userId = await _userService.CreateUserAsync(viewModel);
|
var userId = await _userService.CreateUserAsync(viewModel);
|
||||||
return Response(userId);
|
return Response(userId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Authorize]
|
||||||
[HttpDelete("{id}")]
|
[HttpDelete("{id}")]
|
||||||
public async Task<IActionResult> DeleteUserAsync([FromRoute] Guid id)
|
public async Task<IActionResult> DeleteUserAsync([FromRoute] Guid id)
|
||||||
{
|
{
|
||||||
await _userService.DeleteUserAsync(id);
|
await _userService.DeleteUserAsync(id);
|
||||||
return Response(id);
|
return Response(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Authorize]
|
||||||
[HttpPut]
|
[HttpPut]
|
||||||
public async Task<IActionResult> UpdateUserAsync([FromBody] UpdateUserViewModel viewModel)
|
public async Task<IActionResult> UpdateUserAsync([FromBody] UpdateUserViewModel viewModel)
|
||||||
{
|
{
|
||||||
|
@ -1,12 +1,16 @@
|
|||||||
|
using System.IdentityModel.Tokens.Jwt;
|
||||||
|
using System.Text;
|
||||||
using CleanArchitecture.Application.Extensions;
|
using CleanArchitecture.Application.Extensions;
|
||||||
using CleanArchitecture.Domain.Extensions;
|
using CleanArchitecture.Domain.Extensions;
|
||||||
using CleanArchitecture.gRPC;
|
using CleanArchitecture.gRPC;
|
||||||
using CleanArchitecture.Infrastructure.Database;
|
using CleanArchitecture.Infrastructure.Database;
|
||||||
using CleanArchitecture.Infrastructure.Extensions;
|
using CleanArchitecture.Infrastructure.Extensions;
|
||||||
|
using Microsoft.AspNetCore.Authentication.JwtBearer;
|
||||||
using Microsoft.AspNetCore.Builder;
|
using Microsoft.AspNetCore.Builder;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
using Microsoft.Extensions.Configuration;
|
using Microsoft.Extensions.Configuration;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
using Microsoft.IdentityModel.Tokens;
|
||||||
|
|
||||||
var builder = WebApplication.CreateBuilder(args);
|
var builder = WebApplication.CreateBuilder(args);
|
||||||
|
|
||||||
@ -24,11 +28,23 @@ builder.Services.AddDbContext<ApplicationDbContext>(options =>
|
|||||||
b => b.MigrationsAssembly("CleanArchitecture.Infrastructure"));
|
b => b.MigrationsAssembly("CleanArchitecture.Infrastructure"));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
builder.Services.AddAuthentication(
|
||||||
|
options =>
|
||||||
|
{
|
||||||
|
options.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
|
||||||
|
})
|
||||||
|
.AddJwtBearer(
|
||||||
|
jwtOptions =>
|
||||||
|
{
|
||||||
|
jwtOptions.TokenValidationParameters = CreateTokenValidationParameters();
|
||||||
|
});
|
||||||
|
|
||||||
builder.Services.AddInfrastructure();
|
builder.Services.AddInfrastructure();
|
||||||
builder.Services.AddQueryHandlers();
|
builder.Services.AddQueryHandlers();
|
||||||
builder.Services.AddServices();
|
builder.Services.AddServices();
|
||||||
builder.Services.AddCommandHandlers();
|
builder.Services.AddCommandHandlers();
|
||||||
builder.Services.AddNotificationHandlers();
|
builder.Services.AddNotificationHandlers();
|
||||||
|
builder.Services.AddApiUser();
|
||||||
|
|
||||||
builder.Services.AddMediatR(cfg =>
|
builder.Services.AddMediatR(cfg =>
|
||||||
{
|
{
|
||||||
@ -42,6 +58,7 @@ app.UseSwaggerUI();
|
|||||||
|
|
||||||
app.UseHttpsRedirection();
|
app.UseHttpsRedirection();
|
||||||
|
|
||||||
|
app.UseAuthentication();
|
||||||
app.UseAuthorization();
|
app.UseAuthorization();
|
||||||
|
|
||||||
app.MapControllers();
|
app.MapControllers();
|
||||||
@ -57,5 +74,24 @@ using (IServiceScope scope = app.Services.CreateScope())
|
|||||||
|
|
||||||
app.Run();
|
app.Run();
|
||||||
|
|
||||||
|
TokenValidationParameters CreateTokenValidationParameters()
|
||||||
|
{
|
||||||
|
var result = new TokenValidationParameters
|
||||||
|
{
|
||||||
|
ValidateIssuer = true,
|
||||||
|
ValidateAudience = true,
|
||||||
|
ValidateLifetime = true,
|
||||||
|
ValidateIssuerSigningKey = true,
|
||||||
|
ValidIssuer = builder.Configuration["Auth:Issuer"],
|
||||||
|
ValidAudience = builder.Configuration["Auth:Audience"],
|
||||||
|
IssuerSigningKey = new SymmetricSecurityKey(
|
||||||
|
Encoding.UTF8.GetBytes(
|
||||||
|
builder.Configuration["Auth:Secret"]!)),
|
||||||
|
RequireSignedTokens = false
|
||||||
|
};
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
// Needed for integration tests webapplication factory
|
// Needed for integration tests webapplication factory
|
||||||
public partial class Program { }
|
public partial class Program { }
|
@ -4,5 +4,13 @@
|
|||||||
"Default": "Information",
|
"Default": "Information",
|
||||||
"Microsoft.AspNetCore": "Warning"
|
"Microsoft.AspNetCore": "Warning"
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"ConnectionStrings": {
|
||||||
|
"DefaultConnection": "Server=localhost;Database=clean-architecture;Trusted_Connection=True;MultipleActiveResultSets=true;TrustServerCertificate=True"
|
||||||
|
},
|
||||||
|
"Auth": {
|
||||||
|
"Issuer": "CleanArchitectureServer",
|
||||||
|
"Audience": "CleanArchitectureClient",
|
||||||
|
"Secret": "sD3v061gf8BxXgmxcHss"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,5 +8,10 @@
|
|||||||
"AllowedHosts": "*",
|
"AllowedHosts": "*",
|
||||||
"ConnectionStrings": {
|
"ConnectionStrings": {
|
||||||
"DefaultConnection": "Server=localhost;Database=clean-architecture;Trusted_Connection=True;MultipleActiveResultSets=true;TrustServerCertificate=True"
|
"DefaultConnection": "Server=localhost;Database=clean-architecture;Trusted_Connection=True;MultipleActiveResultSets=true;TrustServerCertificate=True"
|
||||||
|
},
|
||||||
|
"Auth": {
|
||||||
|
"Issuer": "CleanArchitectureServer",
|
||||||
|
"Audience": "CleanArchitectureClient",
|
||||||
|
"Secret": "sD3v061gf8BxXgmxcHss"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,4 +3,5 @@ namespace CleanArchitecture.Application.ViewModels.Users;
|
|||||||
public sealed record CreateUserViewModel(
|
public sealed record CreateUserViewModel(
|
||||||
string Email,
|
string Email,
|
||||||
string Surname,
|
string Surname,
|
||||||
string GivenName);
|
string GivenName,
|
||||||
|
string Password);
|
@ -1,5 +1,6 @@
|
|||||||
using System;
|
using System;
|
||||||
using CleanArchitecture.Domain.Entities;
|
using CleanArchitecture.Domain.Entities;
|
||||||
|
using CleanArchitecture.Domain.Enums;
|
||||||
|
|
||||||
namespace CleanArchitecture.Application.ViewModels.Users;
|
namespace CleanArchitecture.Application.ViewModels.Users;
|
||||||
|
|
||||||
@ -9,6 +10,7 @@ public sealed class UserViewModel
|
|||||||
public string Email { get; set; } = string.Empty;
|
public string Email { get; set; } = string.Empty;
|
||||||
public string GivenName { get; set; } = string.Empty;
|
public string GivenName { get; set; } = string.Empty;
|
||||||
public string Surname { get; set; } = string.Empty;
|
public string Surname { get; set; } = string.Empty;
|
||||||
|
public UserRole Role { get; set; }
|
||||||
|
|
||||||
public static UserViewModel FromUser(User user)
|
public static UserViewModel FromUser(User user)
|
||||||
{
|
{
|
||||||
@ -17,7 +19,8 @@ public sealed class UserViewModel
|
|||||||
Id = user.Id,
|
Id = user.Id,
|
||||||
Email = user.Email,
|
Email = user.Email,
|
||||||
GivenName = user.GivenName,
|
GivenName = user.GivenName,
|
||||||
Surname = user.Surname
|
Surname = user.Surname,
|
||||||
|
Role = user.Role
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
46
CleanArchitecture.Domain/ApiUser.cs
Normal file
46
CleanArchitecture.Domain/ApiUser.cs
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
using System;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Security.Claims;
|
||||||
|
using CleanArchitecture.Domain.Enums;
|
||||||
|
using CleanArchitecture.Domain.Interfaces;
|
||||||
|
using Microsoft.AspNetCore.Http;
|
||||||
|
|
||||||
|
namespace CleanArchitecture.Domain;
|
||||||
|
|
||||||
|
public sealed class ApiUser : IUser
|
||||||
|
{
|
||||||
|
private readonly IHttpContextAccessor _httpContextAccessor;
|
||||||
|
|
||||||
|
public ApiUser(IHttpContextAccessor httpContextAccessor)
|
||||||
|
{
|
||||||
|
_httpContextAccessor = httpContextAccessor;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Guid GetUserId()
|
||||||
|
{
|
||||||
|
var claim = _httpContextAccessor.HttpContext?.User.Claims
|
||||||
|
.FirstOrDefault(x => string.Equals(x.Type, ClaimTypes.NameIdentifier));
|
||||||
|
|
||||||
|
if (Guid.TryParse(claim?.Value, out var userId))
|
||||||
|
{
|
||||||
|
return userId;
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new ArgumentException("Could not parse user id to guid");
|
||||||
|
}
|
||||||
|
|
||||||
|
public UserRole GetUserRole()
|
||||||
|
{
|
||||||
|
var claim = _httpContextAccessor.HttpContext?.User.Claims
|
||||||
|
.FirstOrDefault(x => string.Equals(x.Type, ClaimTypes.Role));
|
||||||
|
|
||||||
|
if (Enum.TryParse(claim?.Value, out UserRole userRole))
|
||||||
|
{
|
||||||
|
return userRole;
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new ArgumentException("Could not parse user role");
|
||||||
|
}
|
||||||
|
|
||||||
|
public string Name => _httpContextAccessor.HttpContext?.User.Identity?.Name ?? string.Empty;
|
||||||
|
}
|
@ -6,8 +6,10 @@
|
|||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<PackageReference Include="BCrypt.Net-Next" Version="4.0.3" />
|
||||||
<PackageReference Include="FluentValidation" Version="11.5.1" />
|
<PackageReference Include="FluentValidation" Version="11.5.1" />
|
||||||
<PackageReference Include="MediatR" Version="12.0.1" />
|
<PackageReference Include="MediatR" Version="12.0.1" />
|
||||||
|
<PackageReference Include="Microsoft.AspNetCore.Http.Abstractions" Version="2.2.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
@ -10,17 +10,20 @@ public sealed class CreateUserCommand : CommandBase
|
|||||||
public string Email { get; }
|
public string Email { get; }
|
||||||
public string Surname { get; }
|
public string Surname { get; }
|
||||||
public string GivenName { get; }
|
public string GivenName { get; }
|
||||||
|
public string Password { get; }
|
||||||
|
|
||||||
public CreateUserCommand(
|
public CreateUserCommand(
|
||||||
Guid userId,
|
Guid userId,
|
||||||
string email,
|
string email,
|
||||||
string surname,
|
string surname,
|
||||||
string givenName) : base(userId)
|
string givenName,
|
||||||
|
string password) : base(userId)
|
||||||
{
|
{
|
||||||
UserId = userId;
|
UserId = userId;
|
||||||
Email = email;
|
Email = email;
|
||||||
Surname = surname;
|
Surname = surname;
|
||||||
GivenName = givenName;
|
GivenName = givenName;
|
||||||
|
Password = password;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override bool IsValid()
|
public override bool IsValid()
|
||||||
|
@ -1,12 +1,14 @@
|
|||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using CleanArchitecture.Domain.Entities;
|
using CleanArchitecture.Domain.Entities;
|
||||||
|
using CleanArchitecture.Domain.Enums;
|
||||||
using CleanArchitecture.Domain.Errors;
|
using CleanArchitecture.Domain.Errors;
|
||||||
using CleanArchitecture.Domain.Events.User;
|
using CleanArchitecture.Domain.Events.User;
|
||||||
using CleanArchitecture.Domain.Interfaces;
|
using CleanArchitecture.Domain.Interfaces;
|
||||||
using CleanArchitecture.Domain.Interfaces.Repositories;
|
using CleanArchitecture.Domain.Interfaces.Repositories;
|
||||||
using CleanArchitecture.Domain.Notifications;
|
using CleanArchitecture.Domain.Notifications;
|
||||||
using MediatR;
|
using MediatR;
|
||||||
|
using BC = BCrypt.Net.BCrypt;
|
||||||
|
|
||||||
namespace CleanArchitecture.Domain.Commands.Users.CreateUser;
|
namespace CleanArchitecture.Domain.Commands.Users.CreateUser;
|
||||||
|
|
||||||
@ -43,11 +45,15 @@ public sealed class CreateUserCommandHandler : CommandHandlerBase,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var passwordHash = BC.HashPassword(request.Password);
|
||||||
|
|
||||||
var user = new User(
|
var user = new User(
|
||||||
request.UserId,
|
request.UserId,
|
||||||
request.Email,
|
request.Email,
|
||||||
request.Surname,
|
request.Surname,
|
||||||
request.GivenName);
|
request.GivenName,
|
||||||
|
passwordHash,
|
||||||
|
UserRole.User);
|
||||||
|
|
||||||
_userRepository.Add(user);
|
_userRepository.Add(user);
|
||||||
|
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using CleanArchitecture.Domain.Enums;
|
||||||
using CleanArchitecture.Domain.Errors;
|
using CleanArchitecture.Domain.Errors;
|
||||||
using CleanArchitecture.Domain.Events.User;
|
using CleanArchitecture.Domain.Events.User;
|
||||||
using CleanArchitecture.Domain.Interfaces;
|
using CleanArchitecture.Domain.Interfaces;
|
||||||
@ -13,14 +14,17 @@ public sealed class DeleteUserCommandHandler : CommandHandlerBase,
|
|||||||
IRequestHandler<DeleteUserCommand>
|
IRequestHandler<DeleteUserCommand>
|
||||||
{
|
{
|
||||||
private readonly IUserRepository _userRepository;
|
private readonly IUserRepository _userRepository;
|
||||||
|
private readonly IUser _user;
|
||||||
|
|
||||||
public DeleteUserCommandHandler(
|
public DeleteUserCommandHandler(
|
||||||
IMediatorHandler bus,
|
IMediatorHandler bus,
|
||||||
IUnitOfWork unitOfWork,
|
IUnitOfWork unitOfWork,
|
||||||
INotificationHandler<DomainNotification> notifications,
|
INotificationHandler<DomainNotification> notifications,
|
||||||
IUserRepository userRepository) : base(bus, unitOfWork, notifications)
|
IUserRepository userRepository,
|
||||||
|
IUser user) : base(bus, unitOfWork, notifications)
|
||||||
{
|
{
|
||||||
_userRepository = userRepository;
|
_userRepository = userRepository;
|
||||||
|
_user = user;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task Handle(DeleteUserCommand request, CancellationToken cancellationToken)
|
public async Task Handle(DeleteUserCommand request, CancellationToken cancellationToken)
|
||||||
@ -43,6 +47,11 @@ public sealed class DeleteUserCommandHandler : CommandHandlerBase,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (_user.GetUserId() != request.UserId || _user.GetUserRole() != UserRole.Admin)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
_userRepository.Remove(user);
|
_userRepository.Remove(user);
|
||||||
|
|
||||||
if (await CommitAsync())
|
if (await CommitAsync())
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
using System;
|
using System;
|
||||||
|
using CleanArchitecture.Domain.Enums;
|
||||||
|
|
||||||
namespace CleanArchitecture.Domain.Commands.Users.UpdateUser;
|
namespace CleanArchitecture.Domain.Commands.Users.UpdateUser;
|
||||||
|
|
||||||
@ -10,17 +11,20 @@ public sealed class UpdateUserCommand : CommandBase
|
|||||||
public string Email { get; }
|
public string Email { get; }
|
||||||
public string Surname { get; }
|
public string Surname { get; }
|
||||||
public string GivenName { get; }
|
public string GivenName { get; }
|
||||||
|
public UserRole Role { get; }
|
||||||
|
|
||||||
public UpdateUserCommand(
|
public UpdateUserCommand(
|
||||||
Guid userId,
|
Guid userId,
|
||||||
string email,
|
string email,
|
||||||
string surname,
|
string surname,
|
||||||
string givenName) : base(userId)
|
string givenName,
|
||||||
|
UserRole role) : base(userId)
|
||||||
{
|
{
|
||||||
UserId = userId;
|
UserId = userId;
|
||||||
Email = email;
|
Email = email;
|
||||||
Surname = surname;
|
Surname = surname;
|
||||||
GivenName = givenName;
|
GivenName = givenName;
|
||||||
|
Role = role;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override bool IsValid()
|
public override bool IsValid()
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using CleanArchitecture.Domain.Entities;
|
||||||
|
using CleanArchitecture.Domain.Enums;
|
||||||
using CleanArchitecture.Domain.Errors;
|
using CleanArchitecture.Domain.Errors;
|
||||||
using CleanArchitecture.Domain.Events.User;
|
using CleanArchitecture.Domain.Events.User;
|
||||||
using CleanArchitecture.Domain.Interfaces;
|
using CleanArchitecture.Domain.Interfaces;
|
||||||
@ -13,14 +15,17 @@ public sealed class UpdateUserCommandHandler : CommandHandlerBase,
|
|||||||
IRequestHandler<UpdateUserCommand>
|
IRequestHandler<UpdateUserCommand>
|
||||||
{
|
{
|
||||||
private readonly IUserRepository _userRepository;
|
private readonly IUserRepository _userRepository;
|
||||||
|
private readonly IUser _user;
|
||||||
|
|
||||||
public UpdateUserCommandHandler(
|
public UpdateUserCommandHandler(
|
||||||
IMediatorHandler bus,
|
IMediatorHandler bus,
|
||||||
IUnitOfWork unitOfWork,
|
IUnitOfWork unitOfWork,
|
||||||
INotificationHandler<DomainNotification> notifications,
|
INotificationHandler<DomainNotification> notifications,
|
||||||
IUserRepository userRepository) : base(bus, unitOfWork, notifications)
|
IUserRepository userRepository,
|
||||||
|
IUser user) : base(bus, unitOfWork, notifications)
|
||||||
{
|
{
|
||||||
_userRepository = userRepository;
|
_userRepository = userRepository;
|
||||||
|
_user = user;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task Handle(UpdateUserCommand request, CancellationToken cancellationToken)
|
public async Task Handle(UpdateUserCommand request, CancellationToken cancellationToken)
|
||||||
@ -41,11 +46,21 @@ public sealed class UpdateUserCommandHandler : CommandHandlerBase,
|
|||||||
ErrorCodes.ObjectNotFound));
|
ErrorCodes.ObjectNotFound));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (_user.GetUserId() != request.UserId || _user.GetUserRole() != UserRole.Admin)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_user.GetUserRole() == UserRole.Admin)
|
||||||
|
{
|
||||||
|
user.SetRole(request.Role);
|
||||||
|
}
|
||||||
|
|
||||||
user.SetEmail(request.Email);
|
user.SetEmail(request.Email);
|
||||||
user.SetSurname(request.Surname);
|
user.SetSurname(request.Surname);
|
||||||
user.SetGivenName(request.GivenName);
|
user.SetGivenName(request.GivenName);
|
||||||
|
|
||||||
_userRepository.Update(user);
|
_userRepository.Update(user);
|
||||||
|
|
||||||
if (await CommitAsync())
|
if (await CommitAsync())
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Diagnostics.CodeAnalysis;
|
using System.Diagnostics.CodeAnalysis;
|
||||||
|
using CleanArchitecture.Domain.Enums;
|
||||||
|
|
||||||
namespace CleanArchitecture.Domain.Entities;
|
namespace CleanArchitecture.Domain.Entities;
|
||||||
|
|
||||||
@ -8,20 +9,26 @@ public class User : Entity
|
|||||||
public string Email { get; private set; }
|
public string Email { get; private set; }
|
||||||
public string GivenName { get; private set; }
|
public string GivenName { get; private set; }
|
||||||
public string Surname { get; private set; }
|
public string Surname { get; private set; }
|
||||||
|
public string Password { get; private set; }
|
||||||
|
public UserRole Role { get; private set; }
|
||||||
|
|
||||||
public string FullName => $"{Surname}, {GivenName}";
|
public string FullName => $"{Surname}, {GivenName}";
|
||||||
|
|
||||||
public User(
|
public User(
|
||||||
Guid id,
|
Guid id,
|
||||||
string email,
|
string email,
|
||||||
string surname,
|
string surname,
|
||||||
string givenName) : base(id)
|
string givenName,
|
||||||
|
string password,
|
||||||
|
UserRole role) : base(id)
|
||||||
{
|
{
|
||||||
Email = email;
|
Email = email;
|
||||||
GivenName = givenName;
|
GivenName = givenName;
|
||||||
Surname = surname;
|
Surname = surname;
|
||||||
|
Password = password;
|
||||||
|
Role = role;
|
||||||
}
|
}
|
||||||
|
|
||||||
[MemberNotNull(nameof(Email))]
|
[MemberNotNull(nameof(Email))]
|
||||||
public void SetEmail(string email)
|
public void SetEmail(string email)
|
||||||
{
|
{
|
||||||
@ -72,4 +79,26 @@ public class User : Entity
|
|||||||
|
|
||||||
Surname = surname;
|
Surname = surname;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[MemberNotNull(nameof(Password))]
|
||||||
|
public void SetPassword(string password)
|
||||||
|
{
|
||||||
|
if (password == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(password));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (password.Length > 100)
|
||||||
|
{
|
||||||
|
throw new ArgumentException(
|
||||||
|
"Password may not be longer than 100 characters");
|
||||||
|
}
|
||||||
|
|
||||||
|
Password = password;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetRole(UserRole role)
|
||||||
|
{
|
||||||
|
Role = role;
|
||||||
|
}
|
||||||
}
|
}
|
7
CleanArchitecture.Domain/Enums/UserRole.cs
Normal file
7
CleanArchitecture.Domain/Enums/UserRole.cs
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
namespace CleanArchitecture.Domain.Enums;
|
||||||
|
|
||||||
|
public enum UserRole
|
||||||
|
{
|
||||||
|
Admin,
|
||||||
|
User
|
||||||
|
}
|
@ -3,6 +3,7 @@ using CleanArchitecture.Domain.Commands.Users.DeleteUser;
|
|||||||
using CleanArchitecture.Domain.Commands.Users.UpdateUser;
|
using CleanArchitecture.Domain.Commands.Users.UpdateUser;
|
||||||
using CleanArchitecture.Domain.EventHandler;
|
using CleanArchitecture.Domain.EventHandler;
|
||||||
using CleanArchitecture.Domain.Events.User;
|
using CleanArchitecture.Domain.Events.User;
|
||||||
|
using CleanArchitecture.Domain.Interfaces;
|
||||||
using MediatR;
|
using MediatR;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
|
||||||
@ -29,4 +30,12 @@ public static class ServiceCollectionExtension
|
|||||||
|
|
||||||
return services;
|
return services;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static IServiceCollection AddApiUser(this IServiceCollection services)
|
||||||
|
{
|
||||||
|
// User
|
||||||
|
services.AddScoped<IUser, ApiUser>();
|
||||||
|
|
||||||
|
return services;
|
||||||
|
}
|
||||||
}
|
}
|
12
CleanArchitecture.Domain/Interfaces/IUser.cs
Normal file
12
CleanArchitecture.Domain/Interfaces/IUser.cs
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
using System;
|
||||||
|
using CleanArchitecture.Domain.Enums;
|
||||||
|
|
||||||
|
namespace CleanArchitecture.Domain.Interfaces;
|
||||||
|
|
||||||
|
public interface IUser
|
||||||
|
{
|
||||||
|
Guid GetUserId();
|
||||||
|
UserRole GetUserRole();
|
||||||
|
|
||||||
|
string Name { get; }
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user