add authorization

This commit is contained in:
Alex Bezdieniezhnykh
2024-11-11 21:07:28 +02:00
parent ca6175da7f
commit 85139b4fd2
12 changed files with 146 additions and 40 deletions
+41 -17
View File
@@ -1,56 +1,80 @@
using Azaion.Common;
using System.Security.Claims;
using Azaion.Common;
using Azaion.Common.Configs;
using Azaion.Common.Database;
using Azaion.Common.Entities;
using Azaion.Common.Requests;
using LinqToDB;
using Microsoft.AspNetCore.Http;
namespace Azaion.Services;
public interface IUserService
{
User? CurrentUser { get; }
Task RegisterUser(RegisterUserRequest request, CancellationToken cancellationToken = default);
Task<User?> ValidateUser(GetResourceRequest request, CancellationToken cancellationToken = default);
Task<User> ValidateUser(string username, string password, string? hardwareId = null, CancellationToken cancellationToken = default);
Task UpdateHardwareId(string username, string hardwareId, CancellationToken cancellationToken = default);
}
public class UserService(IDbFactory dbFactory) : IUserService
public class UserService(IDbFactory dbFactory, IHttpContextAccessor httpContextAccessor) : IUserService
{
public User? CurrentUser
{
get
{
var claims = httpContextAccessor.HttpContext?.User.Claims.ToDictionary(x => x.Type);
if (claims == null)
return null;
Enum.TryParse(claims[ClaimTypes.Role].Value, out RoleEnum role);
return new User
{
Id = claims[ClaimTypes.NameIdentifier].Value,
Email = claims[ClaimTypes.Name].Value,
Role = role,
HardwareId = claims[Constants.HARDWARE_ID].Value,
};
}
}
public async Task RegisterUser(RegisterUserRequest request, CancellationToken cancellationToken = default)
{
await dbFactory.Run(async db =>
{
var existingUser = await db.Users.FirstOrDefaultAsync(u => u.Username == request.Email, token: cancellationToken);
var existingUser = await db.Users.FirstOrDefaultAsync(u => u.Email == request.Email, token: cancellationToken);
if (existingUser != null)
throw new BusinessException(ExceptionEnum.UserExists, "User already exists");
await db.InsertAsync(new User
{
Username = request.Email,
Email = request.Email,
PasswordHash = request.Password.ToHash(),
Role = request.Role
}, token: cancellationToken);
});
}
public async Task<User?> ValidateUser(GetResourceRequest request, CancellationToken cancellationToken = default) =>
public async Task<User> ValidateUser(string username, string password, string? hardwareId = null, CancellationToken cancellationToken = default) =>
await dbFactory.Run(async db =>
{
var user = await db.Users.FirstOrDefaultAsync(x => x.Username == request.Username, token: cancellationToken);
var user = await db.Users.FirstOrDefaultAsync(x => x.Email == username, token: cancellationToken);
if (user == null)
throw new BusinessException(ExceptionEnum.NoUserFound, "No user found");
if (request.Password.ToHash() != user.PasswordHash)
if (password.ToHash() != user.PasswordHash)
throw new BusinessException(ExceptionEnum.PasswordIncorrect, "Passwords do not match");
//If user's hardware Id is empty (usually on the first time login), then write down user
if (string.IsNullOrEmpty(user.HardwareId))
await db.Users.UpdateAsync(x => x.Username == request.Username, u => new User{HardwareId = request.HardwareId}, token: cancellationToken);
else
{
//But if hardware Id exists, it should match with request
if (user.HardwareId != request.HardwareId)
throw new BusinessException(ExceptionEnum.HardwareIdMismatch, "Hardware id mismatch");
}
if (user.Role == RoleEnum.ApiAdmin)
return user;
// For Non-API admins hardwareId should match if it was already set
if (user.HardwareId != null && user.HardwareId != hardwareId)
throw new BusinessException(ExceptionEnum.HardwareIdMismatch, "Hardware id mismatch");
return user;
});
public async Task UpdateHardwareId(string username, string hardwareId, CancellationToken cancellationToken = default) =>
await dbFactory.Run(async db =>
await db.Users.UpdateAsync(x => x.Email == username, u => new User { HardwareId = hardwareId}, token: cancellationToken));
}