Result classes can derive when new instance is created.

This commit is contained in:
max 2024-10-14 03:20:44 +02:00
parent 0fed89e140
commit 17f69824eb
5 changed files with 93 additions and 29 deletions

View File

@ -5,20 +5,18 @@ namespace DotBased.ASP.Auth;
public class AuthDataCache public class AuthDataCache
{ {
public AuthDataCache(IAuthDataRepository dataRepository, BasedAuthConfiguration configuration) public AuthDataCache(BasedAuthConfiguration configuration)
{ {
DataRepository = dataRepository;
_configuration = configuration; _configuration = configuration;
} }
public readonly IAuthDataRepository DataRepository;
private readonly BasedAuthConfiguration _configuration; private readonly BasedAuthConfiguration _configuration;
private readonly CacheNodeCollection<AuthenticationStateModel> _authenticationStateCollection = []; private readonly CacheNodeCollection<AuthenticationStateModel> _authenticationStateCollection = [];
public Result PurgeSessionFromCache(string id) => _authenticationStateCollection.Remove(id) ? Result.Ok() : Result.Failed("Failed to purge session state from cache!"); public Result PurgeSessionFromCache(string id) => _authenticationStateCollection.Remove(id) ? Result.Ok() : Result.Failed("Failed to purge session state from cache! Or the session was not cached...");
public async Task<Result<AuthenticationStateModel>> RequestAuthStateAsync(string id) public async Task<Result<AuthenticationStateModel>> RequestAuthStateAsync(IAuthDataRepository dataRepository, string id)
{ {
if (_authenticationStateCollection.TryGetValue(id, out var node)) if (_authenticationStateCollection.TryGetValue(id, out var node))
{ {
@ -32,7 +30,7 @@ public class AuthDataCache
return Result<AuthenticationStateModel>.Ok(node.Object); return Result<AuthenticationStateModel>.Ok(node.Object);
} }
var dbResult = await DataRepository.GetAuthenticationStateAsync(id); var dbResult = await dataRepository.GetAuthenticationStateAsync(id);
if (!dbResult.Success || dbResult.Value == null) if (!dbResult.Success || dbResult.Value == null)
{ {
_authenticationStateCollection.Remove(id); _authenticationStateCollection.Remove(id);

View File

@ -1,8 +1,17 @@
using DotBased.ASP.Auth.Domains.Identity;
namespace DotBased.ASP.Auth.Domains.Auth; namespace DotBased.ASP.Auth.Domains.Auth;
public class AuthenticationStateModel public class AuthenticationStateModel
{ {
public string Id { get; set; } = string.Empty; public AuthenticationStateModel(UserModel user)
{
UserId = user.Id;
}
public string Id { get; set; } = Guid.NewGuid().ToString();
public string UserId { get; set; }
public DateTime CreationDate { get; set; } = DateTime.Now;
public override bool Equals(object? obj) public override bool Equals(object? obj)
{ {

View File

@ -24,6 +24,7 @@ public class BasedAuthenticationHandler : AuthenticationHandler<BasedAuthenticat
protected override Task<AuthenticateResult> HandleAuthenticateAsync() protected override Task<AuthenticateResult> HandleAuthenticateAsync()
{ {
/*var principal = new ClaimsPrincipal();*/
var principal = new ClaimsPrincipal(new ClaimsIdentity(new List<Claim>() { new Claim(ClaimTypes.Role, "Admin"), new Claim(ClaimTypes.Name, "Anon") }, AuthenticationScheme)); var principal = new ClaimsPrincipal(new ClaimsIdentity(new List<Claim>() { new Claim(ClaimTypes.Role, "Admin"), new Claim(ClaimTypes.Name, "Anon") }, AuthenticationScheme));
var ticket = new AuthenticationTicket(principal, AuthenticationScheme); var ticket = new AuthenticationTicket(principal, AuthenticationScheme);
return Task.FromResult(AuthenticateResult.Success(ticket)); return Task.FromResult(AuthenticateResult.Success(ticket));

View File

@ -1,5 +1,6 @@
using DotBased.ASP.Auth.Domains; using DotBased.ASP.Auth.Domains;
using DotBased.ASP.Auth.Domains.Auth; using DotBased.ASP.Auth.Domains.Auth;
using DotBased.ASP.Auth.Domains.Identity;
using DotBased.Extensions; using DotBased.Extensions;
using DotBased.Logging; using DotBased.Logging;
@ -7,22 +8,44 @@ namespace DotBased.ASP.Auth.Services;
public class AuthService public class AuthService
{ {
public AuthService(AuthDataCache dataCache) public AuthService(IAuthDataRepository authDataRepository, AuthDataCache dataCache)
{ {
_authDataRepository = authDataRepository;
_dataCache = dataCache; _dataCache = dataCache;
_logger = LogService.RegisterLogger(typeof(AuthService)); _logger = LogService.RegisterLogger(typeof(AuthService));
} }
private readonly IAuthDataRepository _authDataRepository;
private readonly AuthDataCache _dataCache; private readonly AuthDataCache _dataCache;
private readonly ILogger _logger; private readonly ILogger _logger;
public async Task<Result<AuthenticationStateModel>> LoginAsync(LoginModel login) public async Task<Result<AuthenticationStateModel>> LoginAsync(LoginModel login)
{ {
if (login.UserName.IsNullOrWhiteSpace()) UserModel? user = null;
return Result<AuthenticationStateModel>.Failed("Username argument is empty!"); Result<UserModel> usrResult;
//var userResult = await _dataProvider.GetUserAsync(string.Empty, login.Email, login.UserName); if (!login.UserName.IsNullOrWhiteSpace())
//TODO: validate user password and create a session state {
return Result<AuthenticationStateModel>.Failed(""); usrResult = await _authDataRepository.GetUserAsync(string.Empty, string.Empty, login.UserName);
if (usrResult is { Success: true, Value: not null })
user = usrResult.Value;
}
else if (!login.Email.IsNullOrWhiteSpace())
{
usrResult = await _authDataRepository.GetUserAsync(string.Empty, login.Email, string.Empty);
if (usrResult is { Success: true, Value: not null })
user = usrResult.Value;
}
else
return Result<AuthenticationStateModel>.Failed("Username & Email is empty, cannot login!");
if (user == null || !usrResult.Success)
return new Result<AuthenticationStateModel>(usrResult);
if (user.PasswordHash != login.Password) //TODO: Hash password and compare
return Result<AuthenticationStateModel>.Failed("Login failed, invalid password.");
var state = new AuthenticationStateModel(user);
await _authDataRepository.CreateAuthenticationStateAsync(state);
return Result<AuthenticationStateModel>.Ok(state);
} }
public async Task<Result> Logout(string state) public async Task<Result> Logout(string state)

View File

@ -1,31 +1,64 @@
namespace DotBased; namespace DotBased;
/// <summary> /// <summary>
/// Simple result class for returning a result state or a message and a exception. /// Simple result class for returning a result state or a message and an exception.
/// </summary> /// </summary>
public class Result(bool success, string message, Exception? exception) public class Result
{ {
public bool Success { get; set; } = success; public Result(bool success, string message, Exception? exception)
public string Message { get; set; } = message; {
public Exception? Exception { get; set; } = exception; Success = success;
Message = message;
Exception = exception;
}
public static Result Ok() => new Result(true, string.Empty, null); public Result(Result bObj)
public static Result Failed(string message, Exception? exception = null) => new Result(false, message, exception); {
Success = bObj.Success;
Message = bObj.Message;
Exception = bObj.Exception;
}
public bool Success { get; set; }
public string Message { get; set; }
public Exception? Exception { get; set; }
public static Result Ok() => new(true, string.Empty, null);
public static Result Failed(string message, Exception? exception = null) => new(false, message, exception);
} }
public class Result<TValue>(bool success, string message, TValue? value, Exception? exception) : Result(success, message, exception) public class Result<TValue> : Result
{ {
public TValue? Value { get; set; } = value; public Result(bool success, string message, TValue? value, Exception? exception) : base(success, message, exception)
{
Value = value;
}
public Result(Result bObj) : base(bObj)
{
public static Result<TValue> Ok(TValue value) => new Result<TValue>(true, string.Empty, value, null); }
public TValue? Value { get; set; }
public static Result<TValue> Ok(TValue value) => new(true, string.Empty, value, null);
public new static Result<TValue> Failed(string message, Exception? exception = null) => public new static Result<TValue> Failed(string message, Exception? exception = null) =>
new Result<TValue>(false, message, default, exception); new(false, message, default, exception);
} }
public class ListResult<TItem>(bool success, string message, int totalCount, IEnumerable<TItem>? items, Exception? exception) : Result(success, message, exception) public class ListResult<TItem> : Result
{ {
public readonly IReadOnlyList<TItem> Items = items != null ? new List<TItem>(items) : new List<TItem>(); public ListResult(bool success, string message, int totalCount, IEnumerable<TItem>? items, Exception? exception) : base(success, message, exception)
{
Items = items != null ? new List<TItem>(items) : new List<TItem>();
TotalCount = totalCount;
}
public ListResult(Result bObj) : base(bObj)
{
Items = new List<TItem>();
}
public readonly IReadOnlyList<TItem> Items;
/// <summary> /// <summary>
/// The amount of items that this result contains. /// The amount of items that this result contains.
/// </summary> /// </summary>
@ -34,11 +67,11 @@ public class ListResult<TItem>(bool success, string message, int totalCount, IEn
/// <summary> /// <summary>
/// The total amount of item that is available. /// The total amount of item that is available.
/// </summary> /// </summary>
public int TotalCount { get; } = totalCount; public int TotalCount { get; }
public static ListResult<TItem> Ok(IEnumerable<TItem> items, int totalCount = -1) => public static ListResult<TItem> Ok(IEnumerable<TItem> items, int totalCount = -1) =>
new ListResult<TItem>(true, string.Empty, totalCount, items, null); new(true, string.Empty, totalCount, items, null);
public new static ListResult<TItem> Failed(string message, Exception? exception = null) => public new static ListResult<TItem> Failed(string message, Exception? exception = null) =>
new ListResult<TItem>(false, message, -1,null, exception); new(false, message, -1, null, exception);
} }