Added authcontroller and logins

This commit is contained in:
quentin 2024-07-09 18:03:42 -05:00
parent ca059ce75d
commit 1086396ccd
5 changed files with 141 additions and 0 deletions

View File

@ -0,0 +1,46 @@
using API.DTO.Base;
using API.DTO.Login;
using API.Services.Interfaces;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.Mvc;
using System.Security.Claims;
namespace API.Controllers
{
[ApiController]
[Route("api/v1/[controller]")]
public class AuthController : ControllerBase
{
private readonly ILogger<AuthController> _logger;
private readonly IUserManager _userManager;
public AuthController(ILogger<AuthController> logger, IUserManager userManager)
{
_logger = logger;
_userManager = userManager;
}
[HttpPost("login")]
public ActionResult<UserDTO> login(UserLoginDTO userLogin)
{
UserDTO? user = _userManager.AuthenticateUser(userLogin);
if (user == null)
return new UnauthorizedResult();
Claim[] claims =
{
new Claim(ClaimTypes.NameIdentifier, user.id.ToString())
};
ClaimsIdentity claimsIdentity = new ClaimsIdentity(claims, CookieAuthenticationDefaults.AuthenticationScheme);
//todo confirm if this is accurate
AuthenticationProperties authProperties = new AuthenticationProperties();
HttpContext.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme, new ClaimsPrincipal(claimsIdentity), authProperties);
return Ok(user);
}
}
}

View File

@ -0,0 +1,12 @@
using System.ComponentModel.DataAnnotations;
namespace API.DTO.Login
{
public class UserLoginDTO
{
public ulong phoneNumber { get; set; }
[MaxLength(100)]
public string password { get; set; } = null!;
}
}

View File

@ -3,10 +3,13 @@ using API.Authentication.Interfaces;
using API.Hashing; using API.Hashing;
using API.Hashing.Interfaces; using API.Hashing.Interfaces;
using API.Services; using API.Services;
using API.Services.Interfaces;
using DAL.Contexts; using DAL.Contexts;
using DAL.Models;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using Serilog; using Serilog;
using System.Reflection; using System.Reflection;
using ConfigurationManager = Microsoft.Extensions.Configuration.ConfigurationManager;
using InvalidOperationException = System.InvalidOperationException; using InvalidOperationException = System.InvalidOperationException;
namespace API namespace API
@ -46,6 +49,19 @@ namespace API
builder.Services.AddTransient<IHashingAlgorithm, Pbkdf2>(); builder.Services.AddTransient<IHashingAlgorithm, Pbkdf2>();
builder.Services.AddTransient<IUserManager, UserManager>(options =>
{
UserService userService = options.GetRequiredService<UserService>();
IHashingFactory hashingFactory = options.GetRequiredService<IHashingFactory>();
ILogger<UserManager> logger = options.GetRequiredService<ILogger<UserManager>>();
HashingType hashingType;
if (!Enum.TryParse(builder.Configuration["preferredHashingType"], out hashingType))
throw new InvalidOperationException($"preferredHashingType not one of {String.Join(", ", Enum.GetNames(typeof(HashingType)))}");
return new UserManager(userService, hashingFactory, logger, hashingType);
});
WebApplication app = builder.Build(); WebApplication app = builder.Build();
if (app.Environment.IsDevelopment()) if (app.Environment.IsDevelopment())

View File

@ -0,0 +1,10 @@
using API.DTO.Base;
using API.DTO.Login;
namespace API.Services.Interfaces
{
public interface IUserManager
{
UserDTO? AuthenticateUser(UserLoginDTO loginDTO);
}
}

View File

@ -0,0 +1,57 @@
using API.DTO.Base;
using API.DTO.Login;
using API.Hashing.Interfaces;
using API.Services.Interfaces;
using DAL.Models;
namespace API.Services
{
public class UserManager : IUserManager
{
private readonly IHashingFactory _hashingFactory;
private readonly ILogger<UserManager> _logger;
private readonly HashingType _preferredHashingType;
private readonly UserService _userService;
public UserManager(UserService userService, IHashingFactory hashingFactory, ILogger<UserManager> logger, HashingType preferredHashingType)
{
_userService = userService;
_hashingFactory = hashingFactory;
_logger = logger;
_preferredHashingType = preferredHashingType;
}
public UserDTO? AuthenticateUser(UserLoginDTO loginDTO)
{
User? user = _userService.getNoAuthentication(x => x.phoneNumber == loginDTO.phoneNumber).FirstOrDefault();
if (user == null)
return null;
IHashingAlgorithm? hashingAlgorithm = _hashingFactory.getAlgorithm(user.hashingType);
if (hashingAlgorithm == null)
{
_logger.Log(LogLevel.Warning, "User id '{id}' has a hashing type '{hashingType}' that isn't recognized by factory '{factory}'. Not logging in.", user.id, user.hashingType, nameof(_hashingFactory));
return null;
}
string hashedPassword = hashingAlgorithm.hash(loginDTO.password, user.salt);
if (!hashedPassword.Equals(user.password))
{
_logger.Log(LogLevel.Information, "Failed login attempt for user id '{id}.", user.id);
return null;
}
if (user.hashingType != _preferredHashingType)
{
// todo The user is logged in at this point. Their hashing type needs to be updated, we need to rehash & salt the password and save it now.
}
UserDTO dto = new UserDTO();
dto.adaptFromModel(user);
return dto;
}
}
}