From 4423dc360f0f66b82776c49d51ae9d18ffdf0e34 Mon Sep 17 00:00:00 2001 From: shept Date: Thu, 17 Apr 2025 01:06:08 +0500 Subject: [PATCH] registration and authorization --- .../Controllers/AuthController.cs | 29 ++++++++++++- .../UserDTOs/UserRegistrationMapper.cs | 17 ++++++++ SurveyBackend/SurveyBackend.API/Program.cs | 11 +++++ .../SurveyBackend.Core/Models/User.cs | 2 +- .../Repositories/IUserRepository.cs | 1 + .../Services/IPasswordHasher.cs | 2 +- .../Services/IUserService.cs | 5 ++- .../Data/ApplicationDbContext.cs | 2 +- .../Repositories/UserRepository.cs | 5 +++ .../Services/AuthorizationService.cs | 42 +++++++++++++++++++ .../Services/Sha256PasswordHasher.cs | 1 + .../Services/UserService.cs | 25 +++++++++++ 12 files changed, 136 insertions(+), 6 deletions(-) create mode 100644 SurveyBackend/SurveyBackend.API/Mappers/UserDTOs/UserRegistrationMapper.cs rename SurveyBackend/{SurveyBackend.Infrastructure => SurveyBackend.Core}/Services/IPasswordHasher.cs (74%) create mode 100644 SurveyBackend/SurveyBackend.Infrastructure/Services/AuthorizationService.cs create mode 100644 SurveyBackend/SurveyBackend.Infrastructure/Services/UserService.cs diff --git a/SurveyBackend/SurveyBackend.API/Controllers/AuthController.cs b/SurveyBackend/SurveyBackend.API/Controllers/AuthController.cs index 93fb89a..d66e555 100644 --- a/SurveyBackend/SurveyBackend.API/Controllers/AuthController.cs +++ b/SurveyBackend/SurveyBackend.API/Controllers/AuthController.cs @@ -1,5 +1,7 @@ using Microsoft.AspNetCore.Mvc; using SurveyBackend.DTOs; +using SurveyBackend.Infrastructure.Services; +using SurveyBackend.Mappers.UserDTOs; namespace SurveyBackend.Controllers; @@ -7,9 +9,32 @@ namespace SurveyBackend.Controllers; [Route("auth")] public class AuthController : ControllerBase { - [HttpPost("login")] - public async Task GetToken([FromBody] UserLoginDto loginData) + private readonly AuthorizationService _authorizationService; + + public AuthController(AuthorizationService authorizationService) { + _authorizationService = authorizationService; + } + + [HttpPost("login")] + public async Task LogIn([FromBody] UserLoginDto loginData) + { + var token = await _authorizationService.LogInUser(loginData.Email, loginData.Password); + return token is null ? Unauthorized() : Ok(new { token = token }); + } + + [HttpPost("register")] + public async Task Register([FromBody] UserRegistrationDto registerData) + { + try + { + await _authorizationService.RegisterUser(UserRegistrationMapper.UserRegistrationToModel(registerData)); + } + catch (Exception ex) + { + return BadRequest(ex.Message); + } + return Ok(); } } \ No newline at end of file diff --git a/SurveyBackend/SurveyBackend.API/Mappers/UserDTOs/UserRegistrationMapper.cs b/SurveyBackend/SurveyBackend.API/Mappers/UserDTOs/UserRegistrationMapper.cs new file mode 100644 index 0000000..4427b77 --- /dev/null +++ b/SurveyBackend/SurveyBackend.API/Mappers/UserDTOs/UserRegistrationMapper.cs @@ -0,0 +1,17 @@ +using SurveyBackend.Core.Models; +using SurveyBackend.Core.Services; +using SurveyBackend.DTOs; +using SurveyBackend.Infrastructure.Services; + +namespace SurveyBackend.Mappers.UserDTOs; + +public static class UserRegistrationMapper +{ + public static User UserRegistrationToModel(UserRegistrationDto dto) => new User + { + Email = dto.Email, + FirstName = dto.FirstName, + LastName = dto.LastName, + Password = dto.Password, + }; +} \ No newline at end of file diff --git a/SurveyBackend/SurveyBackend.API/Program.cs b/SurveyBackend/SurveyBackend.API/Program.cs index 2aa90b2..d15021d 100644 --- a/SurveyBackend/SurveyBackend.API/Program.cs +++ b/SurveyBackend/SurveyBackend.API/Program.cs @@ -2,8 +2,12 @@ using System.Text; using Microsoft.AspNetCore.Authentication.JwtBearer; using Microsoft.EntityFrameworkCore; using Microsoft.IdentityModel.Tokens; +using SurveyBackend.Core.Repositories; +using SurveyBackend.Core.Services; using SurveyBackend.Infrastructure; using SurveyBackend.Infrastructure.Data; +using SurveyBackend.Infrastructure.Repositories; +using SurveyBackend.Infrastructure.Services; using SurveyLib.Core.Repositories; using SurveyLib.Core.Services; using SurveyLib.Infrastructure.EFCore.Data; @@ -27,6 +31,13 @@ public class Program builder.Services.AddScoped(provider => provider.GetRequiredService()); + builder.Services.AddScoped(); + builder.Services.AddScoped(); + + builder.Services.AddScoped(); + + builder.Services.AddScoped(); + builder.Services.AddScoped(); builder.Services.AddScoped(); diff --git a/SurveyBackend/SurveyBackend.Core/Models/User.cs b/SurveyBackend/SurveyBackend.Core/Models/User.cs index 78f2286..257d4fa 100644 --- a/SurveyBackend/SurveyBackend.Core/Models/User.cs +++ b/SurveyBackend/SurveyBackend.Core/Models/User.cs @@ -4,7 +4,7 @@ namespace SurveyBackend.Core.Models; public class User { - public string Id { get; set; } + public int Id { get; set; } public string Email { get; set; } public string FirstName { get; set; } public string LastName { get; set; } diff --git a/SurveyBackend/SurveyBackend.Core/Repositories/IUserRepository.cs b/SurveyBackend/SurveyBackend.Core/Repositories/IUserRepository.cs index 791059a..311742b 100644 --- a/SurveyBackend/SurveyBackend.Core/Repositories/IUserRepository.cs +++ b/SurveyBackend/SurveyBackend.Core/Repositories/IUserRepository.cs @@ -4,4 +4,5 @@ namespace SurveyBackend.Core.Repositories; public interface IUserRepository : IGenericRepository { + public Task GetUserByEmail(string email); } \ No newline at end of file diff --git a/SurveyBackend/SurveyBackend.Infrastructure/Services/IPasswordHasher.cs b/SurveyBackend/SurveyBackend.Core/Services/IPasswordHasher.cs similarity index 74% rename from SurveyBackend/SurveyBackend.Infrastructure/Services/IPasswordHasher.cs rename to SurveyBackend/SurveyBackend.Core/Services/IPasswordHasher.cs index 52d1427..6e2ec29 100644 --- a/SurveyBackend/SurveyBackend.Infrastructure/Services/IPasswordHasher.cs +++ b/SurveyBackend/SurveyBackend.Core/Services/IPasswordHasher.cs @@ -1,4 +1,4 @@ -namespace SurveyBackend.Infrastructure.Services; +namespace SurveyBackend.Core.Services; public interface IPasswordHasher { diff --git a/SurveyBackend/SurveyBackend.Core/Services/IUserService.cs b/SurveyBackend/SurveyBackend.Core/Services/IUserService.cs index 7d97a29..bb40cdf 100644 --- a/SurveyBackend/SurveyBackend.Core/Services/IUserService.cs +++ b/SurveyBackend/SurveyBackend.Core/Services/IUserService.cs @@ -1,6 +1,9 @@ +using SurveyBackend.Core.Models; + namespace SurveyBackend.Core.Services; public interface IUserService { - + public Task GetUserByEmail(string email); + public Task CreateUserAsync(User user); } \ No newline at end of file diff --git a/SurveyBackend/SurveyBackend.Infrastructure/Data/ApplicationDbContext.cs b/SurveyBackend/SurveyBackend.Infrastructure/Data/ApplicationDbContext.cs index 66a0468..af8eed6 100644 --- a/SurveyBackend/SurveyBackend.Infrastructure/Data/ApplicationDbContext.cs +++ b/SurveyBackend/SurveyBackend.Infrastructure/Data/ApplicationDbContext.cs @@ -13,7 +13,7 @@ public class ApplicationDbContext : SurveyDbContext public ApplicationDbContext(DbContextOptions options) : base(options) { - + Database.EnsureCreated(); } protected override void OnModelCreating(ModelBuilder modelBuilder) diff --git a/SurveyBackend/SurveyBackend.Infrastructure/Repositories/UserRepository.cs b/SurveyBackend/SurveyBackend.Infrastructure/Repositories/UserRepository.cs index bd1980d..86124da 100644 --- a/SurveyBackend/SurveyBackend.Infrastructure/Repositories/UserRepository.cs +++ b/SurveyBackend/SurveyBackend.Infrastructure/Repositories/UserRepository.cs @@ -41,4 +41,9 @@ public class UserRepository : IUserRepository _context.Users.Remove(entity); await _context.SaveChangesAsync(); } + + public async Task GetUserByEmail(string email) + { + return await _context.Users.FirstOrDefaultAsync(u => u.Email == email); + } } \ No newline at end of file diff --git a/SurveyBackend/SurveyBackend.Infrastructure/Services/AuthorizationService.cs b/SurveyBackend/SurveyBackend.Infrastructure/Services/AuthorizationService.cs new file mode 100644 index 0000000..10e244e --- /dev/null +++ b/SurveyBackend/SurveyBackend.Infrastructure/Services/AuthorizationService.cs @@ -0,0 +1,42 @@ +using SurveyBackend.Core.Models; +using SurveyBackend.Core.Services; +using SurveyBackend.Infrastructure.Helpers; + +namespace SurveyBackend.Infrastructure.Services; + +public class AuthorizationService +{ + private readonly IUserService _userService; + private readonly IPasswordHasher _passwordHasher; + + public AuthorizationService(IUserService userService, IPasswordHasher passwordHasher) + { + _userService = userService; + _passwordHasher = passwordHasher; + } + + public async Task LogInUser(string email, string password) + { + var user = await _userService.GetUserByEmail(email); + if (user is null || !_passwordHasher.Verify(password, user.Password)) + { + return null; + } + + var token = TokenHelper.GetAuthToken(user); + return token; + } + + public async Task RegisterUser(User user) + { + var existingUser = await _userService.GetUserByEmail(user.Email); + if (existingUser is not null) + { + throw new Exception("Email already exists"); + } + + user.Password = _passwordHasher.HashPassword(user.Password); + + await _userService.CreateUserAsync(user); + } +} \ No newline at end of file diff --git a/SurveyBackend/SurveyBackend.Infrastructure/Services/Sha256PasswordHasher.cs b/SurveyBackend/SurveyBackend.Infrastructure/Services/Sha256PasswordHasher.cs index f513cff..b6cde0d 100644 --- a/SurveyBackend/SurveyBackend.Infrastructure/Services/Sha256PasswordHasher.cs +++ b/SurveyBackend/SurveyBackend.Infrastructure/Services/Sha256PasswordHasher.cs @@ -1,4 +1,5 @@ using System.Security.Cryptography; +using SurveyBackend.Core.Services; namespace SurveyBackend.Infrastructure.Services; diff --git a/SurveyBackend/SurveyBackend.Infrastructure/Services/UserService.cs b/SurveyBackend/SurveyBackend.Infrastructure/Services/UserService.cs new file mode 100644 index 0000000..f0f4b4e --- /dev/null +++ b/SurveyBackend/SurveyBackend.Infrastructure/Services/UserService.cs @@ -0,0 +1,25 @@ +using SurveyBackend.Core.Models; +using SurveyBackend.Core.Repositories; +using SurveyBackend.Core.Services; + +namespace SurveyBackend.Infrastructure.Services; + +public class UserService : IUserService +{ + private readonly IUserRepository _userRepository; + + public UserService(IUserRepository userRepository) + { + _userRepository = userRepository; + } + + public async Task GetUserByEmail(string email) + { + return await _userRepository.GetUserByEmail(email); + } + + public async Task CreateUserAsync(User user) + { + await _userRepository.AddAsync(user); + } +} \ No newline at end of file