From bdb945b3bd52533182bde6c08700af178cce78e1 Mon Sep 17 00:00:00 2001 From: LilleBRG Date: Wed, 14 Aug 2024 10:28:12 +0200 Subject: [PATCH] Login with made user works --- API/API.csproj | 1 + API/Application/Users/Commands/LoginUser.cs | 61 +++++++++++++++++++ API/Controllers/UsersController.cs | 20 +++++- .../Repositories/IUserRepository.cs | 1 + .../Repositories/UserRepository.cs | 6 ++ API/Program.cs | 28 +++++++++ API/appsettings.Development.json | 5 ++ 7 files changed, 120 insertions(+), 2 deletions(-) create mode 100644 API/Application/Users/Commands/LoginUser.cs diff --git a/API/API.csproj b/API/API.csproj index b65d4fd..f8ed32e 100644 --- a/API/API.csproj +++ b/API/API.csproj @@ -12,6 +12,7 @@ + all diff --git a/API/Application/Users/Commands/LoginUser.cs b/API/Application/Users/Commands/LoginUser.cs new file mode 100644 index 0000000..2659503 --- /dev/null +++ b/API/Application/Users/Commands/LoginUser.cs @@ -0,0 +1,61 @@ +using API.Models; +using API.Persistence.Repositories; +using Microsoft.AspNetCore.Mvc; +using Microsoft.EntityFrameworkCore; +using Microsoft.IdentityModel.Tokens; +using Microsoft.VisualStudio.Web.CodeGenerators.Mvc.Templates.BlazorIdentity.Pages; +using System.Configuration; +using System.IdentityModel.Tokens.Jwt; +using System.Security.Claims; +using System.Text; + +namespace API.Application.Users.Commands +{ + public class LoginUser + { + private readonly IUserRepository _repository; + private readonly IConfiguration _configuration; + + public LoginUser(IUserRepository repository, IConfiguration configuration) + { + _repository = repository; + _configuration = configuration; + } + + public async Task Handle(LoginDTO loginDTO) + { + User user = await _repository.QueryUserByEmailAsync(loginDTO.Email); + if (user == null || !BCrypt.Net.BCrypt.Verify(loginDTO.Password, user.HashedPassword)) + { + return new UnauthorizedObjectResult(new { message = "Invalid email or password." }); + } + var token = GenerateJwtToken(user); + + return new OkObjectResult(token); + + } + + private string GenerateJwtToken(User user) + { + var claims = new[] + { + new Claim(JwtRegisteredClaimNames.Sub, user.Id), + new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()), + new Claim(ClaimTypes.Name, user.Username) + }; + + var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes + (_configuration["JwtSettings:Key"])); + var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256); + + var token = new JwtSecurityToken( + _configuration["JwtSettings:Issuer"], + _configuration["JwtSettings:Audience"], + claims, + expires: DateTime.Now.AddMinutes(30), + signingCredentials: creds); + + return new JwtSecurityTokenHandler().WriteToken(token); + } + } +} diff --git a/API/Controllers/UsersController.cs b/API/Controllers/UsersController.cs index d16b6f4..8c59cfa 100644 --- a/API/Controllers/UsersController.cs +++ b/API/Controllers/UsersController.cs @@ -1,8 +1,13 @@ using API.Application.Users.Commands; using API.Application.Users.Queries; using API.Models; +using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using Microsoft.EntityFrameworkCore; +using Microsoft.IdentityModel.Tokens; +using System.IdentityModel.Tokens.Jwt; +using System.Security.Claims; +using System.Text; using System.Text.RegularExpressions; namespace API.Controllers @@ -16,20 +21,31 @@ namespace API.Controllers private readonly CreateUser _createUser; private readonly UpdateUser _updateUser; private readonly DeleteUser _deleteUser; + private readonly LoginUser _loginUser; public UsersController( QueryAllUsers queryAllUsers, QueryUserById queryUserById, CreateUser createUser, UpdateUser updateUser, - DeleteUser deleteUser) + DeleteUser deleteUser, + LoginUser loginUser) { _queryAllUsers = queryAllUsers; _queryUserById = queryUserById; _createUser = createUser; _updateUser = updateUser; _deleteUser = deleteUser; + _loginUser = loginUser; } + + // POST: api/Users/login + [HttpPost("login")] + public async Task Login(LoginDTO login) + { + return await _loginUser.Handle(login); + } + // GET: api/Users [HttpGet] public async Task>> GetUsers() @@ -67,6 +83,6 @@ namespace API.Controllers public async Task DeleteUser(string id) { return await _deleteUser.Handle(id); - } + } } } diff --git a/API/Persistence/Repositories/IUserRepository.cs b/API/Persistence/Repositories/IUserRepository.cs index bf9fe92..690210f 100644 --- a/API/Persistence/Repositories/IUserRepository.cs +++ b/API/Persistence/Repositories/IUserRepository.cs @@ -8,6 +8,7 @@ namespace API.Persistence.Repositories Task DeleteUserAsync(string id); Task> QueryAllUsersAsync(); Task QueryUserByIdAsync(string id); + Task QueryUserByEmailAsync(string email); Task UpdateUserAsync(User user); } } \ No newline at end of file diff --git a/API/Persistence/Repositories/UserRepository.cs b/API/Persistence/Repositories/UserRepository.cs index 901f7eb..1bc1fdf 100644 --- a/API/Persistence/Repositories/UserRepository.cs +++ b/API/Persistence/Repositories/UserRepository.cs @@ -1,5 +1,6 @@ using API.Models; using Microsoft.EntityFrameworkCore; +using Microsoft.VisualStudio.Web.CodeGenerators.Mvc.Templates.BlazorIdentity.Pages; namespace API.Persistence.Repositories { @@ -70,5 +71,10 @@ namespace API.Persistence.Repositories return true; } + public async Task QueryUserByEmailAsync(string email) + { + return await _context.Users.SingleOrDefaultAsync(u => u.Email == email); + + } } } diff --git a/API/Program.cs b/API/Program.cs index c239519..0d863e4 100644 --- a/API/Program.cs +++ b/API/Program.cs @@ -1,7 +1,10 @@ using API.Application.Users.Commands; using API.Application.Users.Queries; using API.Persistence.Repositories; +using Microsoft.AspNetCore.Authentication.JwtBearer; using Microsoft.EntityFrameworkCore; +using Microsoft.IdentityModel.Tokens; +using System.Text; namespace API { @@ -33,10 +36,35 @@ namespace API builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddScoped(); + builder.Services.AddScoped(); builder.Services.AddScoped(); + IConfiguration Configuration = builder.Configuration; + // Configure JWT Authentication + builder.Services.AddAuthentication(x => + { + x.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme; + x.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme; + x.DefaultScheme = JwtBearerDefaults.AuthenticationScheme; + }).AddJwtBearer(x => + { + x.TokenValidationParameters = new TokenValidationParameters + { + ValidIssuer = Configuration["JwtSettings:Issuer"], + ValidAudience = Configuration["JwtSettings:Audience"], + IssuerSigningKey = new SymmetricSecurityKey + ( + Encoding.UTF8.GetBytes(Configuration["JwtSettings:Key"]) + ), + ValidateIssuer = true, + ValidateAudience = true, + ValidateLifetime = true, + ValidateIssuerSigningKey = true + }; + }); + var connectionString = Configuration.GetConnectionString("DefaultConnection") ?? Environment.GetEnvironmentVariable("DEFAULT_CONNECTION"); builder.Services.AddDbContext(options => options.UseSqlite(connectionString)); diff --git a/API/appsettings.Development.json b/API/appsettings.Development.json index f274806..802dbd0 100644 --- a/API/appsettings.Development.json +++ b/API/appsettings.Development.json @@ -1,4 +1,9 @@ { + "JwtSettings": { + "Issuer": "Flutter-SkanTravels", + "Audience": "Mercantec-Elever", + "Key": "DenHerMåAldrigVæreOffentligKunIDetteDemoProjekt" + }, "Logging": { "LogLevel": { "Default": "Information",