Registration rework

+ InvitesRepository
+ AdminsRepository
+ rework jwt
This commit is contained in:
Artemy
2025-06-24 14:27:08 +07:00
parent 410a1ce1cc
commit ce013eae49
37 changed files with 2084 additions and 29 deletions
+6 -6
View File
@@ -20,7 +20,7 @@ public class AuthController : Controller
[HttpPost("register")]// api/auth/register
[RequireHttps]
public async Task<IActionResult> Register([FromBody] UserDto userDto)
public async Task<IActionResult> Register([FromBody] RegistrationDto registrationDto)
{
try
{
@@ -29,25 +29,25 @@ public class AuthController : Controller
return BadRequest(ModelState);
}
var token = await _accountService.RegistrationAsync(userDto.Name, userDto.Password);
_logger.LogInformation($"Register request for {userDto.Name}");
var token = await _accountService.RegistrationAsync(registrationDto.Name, registrationDto.Password, registrationDto.InviteLink);
_logger.LogInformation($"Register request for {registrationDto.Name}");
return Ok(new { token });
}
catch (UserAlreadyExistException ex)
{
_logger.LogWarning(ex, $"Registration failed for user {userDto.Name}");
_logger.LogWarning(ex, $"Registration failed for user {registrationDto.Name}");
return BadRequest("Registration failed: user already exists.");
}
catch (Exception ex)
{
_logger.LogError(ex, "Unexpected error during registration for user {Name}", userDto.Name);
_logger.LogError(ex, "Unexpected error during registration for user {Name}", registrationDto.Name);
return StatusCode(500, "An unexpected error occurred. Please try again later.");
}
}
[HttpPost("login")]// api/auth/login
[RequireHttps]
public async Task<IActionResult> Login([FromBody] UserDto userDto)
public async Task<IActionResult> Login([FromBody] LoginDto userDto)
{
try
{
+1 -1
View File
@@ -7,7 +7,7 @@ namespace Govor.API.Controllers;
[ApiController]
[Route("api/admin/[controller]")]
//[Authorize(Roles = "Admin")]
[Authorize(Roles = "Admin")]
public class UsersController : Controller
{
private readonly ILogger<UsersController> _logger;
+36 -5
View File
@@ -1,3 +1,4 @@
using System.Security.Cryptography;
using System.Text;
using Govor.API.Hubs;
using Govor.API.Services;
@@ -8,6 +9,8 @@ using Govor.API.Services.Authentication.Interfaces;
using Govor.Core.Infrastructure.Extensions;
using Govor.Core.Infrastructure.Validators;
using Govor.Core.Models;
using Govor.Core.Repositories.Admins;
using Govor.Core.Repositories.Invaites;
using Govor.Core.Repositories.MediasAttachments;
using Govor.Core.Repositories.Messages;
using Govor.Core.Repositories.Users;
@@ -16,6 +19,7 @@ using Govor.Data.Repositories;
using Microsoft.EntityFrameworkCore;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.IdentityModel.Tokens;
using Microsoft.OpenApi.Models;
var builder = WebApplication.CreateBuilder(args);
@@ -69,9 +73,6 @@ builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
builder.Services.AddAuthorization();
builder.Services.AddControllers();
builder.Services.AddScoped<IPasswordHasher, PasswordHasher>();
@@ -84,6 +85,8 @@ builder.Services.AddScoped<IObjectValidator<MediaAttachments>, MediaAttachmentsV
builder.Services.AddScoped<IMessagesRepository, MessagesRepository>();
builder.Services.AddScoped<IMediaAttachmentsRepository, MediaAttachmentsRepository>();
builder.Services.AddScoped<IUsersAdministration, UsersService>();
builder.Services.AddScoped<IInvitesRepository, InvitesRepository>();
builder.Services.AddScoped<IAdminsRepository, AdminsRepository>();
builder.Services.AddDbContext<GovorDbContext>(
options =>
@@ -93,7 +96,32 @@ builder.Services.AddDbContext<GovorDbContext>(
);
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
builder.Services.AddSwaggerGen(options =>
{
options.SwaggerDoc("v1", new OpenApiInfo { Title = "Govor API", Version = "v1" });
options.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme
{
Description = "JWT Authorization header using the Bearer scheme. Example: 'Bearer {token}'",
Name = "Authorization",
In = ParameterLocation.Header,
Type = SecuritySchemeType.Http,
Scheme = "bearer"
});
options.AddSecurityRequirement(new OpenApiSecurityRequirement
{
{
new OpenApiSecurityScheme
{
Reference = new OpenApiReference { Type = ReferenceType.SecurityScheme, Id = "Bearer" }
},
Array.Empty<string>()
}
});
});
//builder.Services.AddOpenApi();
var app = builder.Build();
@@ -102,11 +130,12 @@ var app = builder.Build();
if (app.Environment.IsDevelopment())
{
//app.MapOpenApi();
app.UseSwagger();
app.UseSwaggerUI();
}
app.UseHttpsRedirection();
app.UseRouting();
@@ -117,6 +146,8 @@ app.UseAuthorization();
app.MapControllers();
app.MapHub<ChatsHub>("/api/chats");
app.MapSwagger().RequireAuthorization();
app.Map("/", () => "Not for browsers");
app.Run();
@@ -4,6 +4,8 @@ using Govor.Core.Infrastructure.Extensions;
using Govor.Core.Models;
using Govor.Core.Repositories.Users;
using Govor.API.Services;
using Govor.Core.Repositories.Admins;
using Govor.Core.Repositories.Invaites;
namespace Govor.API.Services.Authentication;
@@ -13,38 +15,64 @@ public class AuthService : IAccountService
private readonly IPasswordHasher _passwordHasher;
private readonly IJwtService _jwtService;
private readonly IUsersRepository _usersRepository;
private readonly IInvitesRepository _invitesRepository;
private readonly IAdminsRepository _adminsRepository;
public AuthService(IUsersRepository usersRepository, IJwtService jwtService, IPasswordHasher passwordHasher)
public AuthService(IUsersRepository usersRepository,
IJwtService jwtService,
IPasswordHasher passwordHasher,
IInvitesRepository invitesRepository,
IAdminsRepository adminsRepository)
{
_usersRepository = usersRepository;
_jwtService = jwtService;
_passwordHasher = passwordHasher;
_invitesRepository = invitesRepository;
_adminsRepository = adminsRepository;
}
public async Task<string> RegistrationAsync(string name, string password)
public async Task<string> RegistrationAsync(string name, string password, string inviteCode)
{
// 1. Проверка существования имени
if (await _usersRepository.ExistsUsernameAsync(name))
throw new UserAlreadyExistException(name);
// 2. Проверка валидности инвайта
var invite = await _invitesRepository.GetByCodeAsync(inviteCode);
// 3. Генерация пароля
var passwordHash = _passwordHasher.Hash(password);
// 4. Создание пользователя
var user = new User
{
Id = Guid.NewGuid(),
Username = name,
Description = string.Empty,
PasswordHash = passwordHash,
CreatedOn = DateOnly.FromDateTime(DateTime.Now),
Description = string.Empty,
CreatedOn = DateOnly.FromDateTime(DateTime.UtcNow),
IconId = Guid.NewGuid(),
WasOnline = DateTime.UtcNow
//Role = role == "Admin" ? "Admin" : "User" // Ограничение ролей
WasOnline = DateTime.UtcNow,
InviteId = invite.Id
};
// 5. Добавление пользователя
await _usersRepository.AddAsync(user);
// 6. Назначение роли, если инвайт — админский
if (invite.IsAdmin)
{
await _adminsRepository.AddAsync(new Admin
{
UserId = user.Id
});
}
// 7. Генерация токена
return _jwtService.GenerateJwtToken(user);
}
public async Task<string> LoginAsync(string name, string password)
{
if (await _usersRepository.ExistsUsernameAsync(name) == false)
@@ -4,6 +4,6 @@ namespace Govor.API.Services.Authentication.Interfaces;
public interface IAccountService
{
public Task<string> RegistrationAsync(string name, string password);
public Task<string> RegistrationAsync(string name, string password, string inviteCode);
public Task<string> LoginAsync(string name, string password);
}
@@ -3,6 +3,8 @@ using System.Security.Claims;
using System.Text;
using Govor.API.Services.Authentication.Interfaces;
using Govor.Core.Models;
using Govor.Core.Repositories.Admins;
using Govor.Core.Repositories.Invaites;
using Microsoft.Extensions.Options;
using Microsoft.IdentityModel.Tokens;
@@ -11,14 +13,22 @@ namespace Govor.API.Services.Authentication;
public class JwtService : IJwtService
{
private JwtOption _jwtOption;
private IInvitesRepository _invitesRepository;
public JwtService(IOptions<JwtOption> options)
{
_jwtOption = options.Value;
}
public string GenerateJwtToken(User user)
{
Claim[] claims = [new("userID", user.Id.ToString())];
var invite = _invitesRepository.GetByIdAsync(user.InviteId).Result;
var claims = new[]
{
new Claim("userID", user.Id.ToString()),
new Claim(ClaimTypes.Role, invite.IsAdmin ? "Admin" : "User", ClaimValueTypes.String)
};
var singing = new SigningCredentials(
new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_jwtOption.SecretKeу)),