Merge branch 'Sec_14_Seguridad_ASP.NET/60_Interfaces_Login_Register' into dev

This commit is contained in:
Alejandro Sarmiento
2024-02-19 19:44:38 +01:00
4 changed files with 134 additions and 2 deletions

View File

@@ -0,0 +1,13 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace CleanArchitecture.Application.Constants
{
public static class CustomClaimTypes
{
public const string Uid = "Uid";
}
}

View File

@@ -2,7 +2,7 @@
{
public class AuthResponse
{
public string Id { get; set; } = string.Empty;
public string UserId { get; set; } = string.Empty;
public string Username { get; set; } = string.Empty;
public string Email { get; set; } = string.Empty;
public string Token { get; set; } = string.Empty;

View File

@@ -6,6 +6,6 @@ namespace CleanArchitecture.Application.Models.Identity
public string Key { get; set; } = string.Empty;
public string Issuer { get; set; } = string.Empty;
public string Audience { get; set; } = string.Empty;
public double DuracionInMinutes { get; set; }
public double DurationInMinutes { get; set; }
}
}

View File

@@ -0,0 +1,119 @@
using CleanArchitecture.Application.Constants;
using CleanArchitecture.Application.Contracts.Identity;
using CleanArchitecture.Application.Models.Identity;
using CleanArchitecture.Identity.Models;
using Microsoft.AspNetCore.Identity;
using Microsoft.IdentityModel.Tokens;
using Newtonsoft.Json.Linq;
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using System.Text;
namespace CleanArchitecture.Identity.Services
{
public class AuthService : IAuthService
{
private readonly UserManager<ApplicationUser> userManager;
private readonly SignInManager<ApplicationUser> signInManager;
private readonly JwtSettings jwtSettings;
public AuthService(UserManager<ApplicationUser> _userManager, SignInManager<ApplicationUser> _signInManager, JwtSettings _jwtSettings)
{
userManager = _userManager;
signInManager = _signInManager;
jwtSettings = _jwtSettings;
}
public async Task<AuthResponse> Login(AuthRequest request)
{
var user = await userManager.FindByEmailAsync(request.Email);
if (user == null)
{
throw new Exception($"User with email: {request.Email} does not exist");
}
var result = await signInManager.CheckPasswordSignInAsync(user, request.Password, false);
if (!result.Succeeded)
{
throw new Exception("Invalid Login Attempt");
}
var token = await GenerateToken(user);
var authResponse = new AuthResponse
{
UserId = user.Id,
Token = new JwtSecurityTokenHandler().WriteToken(token),
Email = user.Email!,
Username = user.UserName!
};
return authResponse;
}
public async Task<RegistrationResponse> Register(RegistrationRequest request)
{
var existingUser = await userManager.FindByEmailAsync(request.Email);
if (existingUser != null)
{
throw new Exception($"User with email: {request.Email} already exists");
}
var existingEmail = await userManager.FindByEmailAsync(request.Email);
if (existingEmail != null)
{
throw new Exception($"Email: {request.Email} is already in use");
}
var newUser = new ApplicationUser
{
Nombre = request.Nombre,
Apellidos = request.Apellidos,
Email = request.Email,
UserName = request.Username
};
var result = await userManager.CreateAsync(newUser, request.Password);
if (!result.Succeeded)
{
var errors = string.Empty;
foreach (var error in result.Errors)
{
errors += $"{error.Description}, ";
}
throw new Exception($"User Registration has failed: {errors}");
}
var token = await GenerateToken(newUser);
var registrationResponse = new RegistrationResponse
{
UserId = newUser.Id,
Email = newUser.Email,
Token = new JwtSecurityTokenHandler().WriteToken(token),
Username = newUser.UserName
};
return registrationResponse;
}
private async Task<JwtSecurityToken> GenerateToken(ApplicationUser user)
{
var userClaims = await userManager.GetClaimsAsync(user);
var roles = await userManager.GetRolesAsync(user);
var roleClaims = roles.Select(role => new Claim(ClaimTypes.Role, role));
var claims = new[]
{
new Claim(JwtRegisteredClaimNames.Sub, user.UserName!),
new Claim(JwtRegisteredClaimNames.Email, user.Email!),
new Claim(CustomClaimTypes.Uid, user.Id),
}.Union(userClaims).Union(roleClaims);
var symmetricSecurityKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(jwtSettings.Key));
var signingCredentials = new SigningCredentials(symmetricSecurityKey, SecurityAlgorithms.HmacSha256);
var token = new JwtSecurityToken(
issuer: jwtSettings.Issuer,
audience: jwtSettings.Audience,
claims: claims,
notBefore: DateTime.UtcNow,
expires: DateTime.UtcNow.AddMinutes(jwtSettings.DurationInMinutes),
signingCredentials: signingCredentials);
return token;
}
}
}