[ADD] Pwd validator, reworked classes

This commit is contained in:
max 2024-12-26 20:01:57 +01:00
parent ebfafa2f29
commit 172d5838e7
8 changed files with 83 additions and 12 deletions

View File

@ -21,9 +21,11 @@ public static class AuthorityProviderExtensions
services.AddOptions();
services.Configure<AuthorityOptions>(optionsAction);
}
services.TryAddScoped<ICryptographer, Cryptographer>();
services.TryAddScoped<IPasswordHasher, PasswordHasher>();
services.TryAddScoped<IPasswordValidator<TUser>, PasswordOptionsValidator<TUser>>();
services.TryAddScoped<IPasswordValidator<TUser>, PasswordEqualsValidator<TUser>>();
services.TryAddScoped<IUserValidator<TUser>, UserValidator<TUser>>();
/*services.TryAddScoped<IEmailVerifier, EmailVerifier>();
services.TryAddScoped<IPhoneNumberVerifier, PhoneNumberVerifier>();
@ -44,4 +46,20 @@ public static class AuthorityProviderExtensions
{
return builder;
}
private static Type GetBaseGenericArgumentType<TModel>(Type baseType)
{
var userGenericBaseTypeDefinition = typeof(TModel).BaseType?.GetGenericTypeDefinition();
if (userGenericBaseTypeDefinition != null && userGenericBaseTypeDefinition == baseType)
{
var userBaseGenericArguments = userGenericBaseTypeDefinition.GetGenericArguments();
if (userBaseGenericArguments.Length <= 0)
{
throw new ArgumentException("Base implementation does not have the required generic argument.", nameof(TModel));
}
return userBaseGenericArguments[0];
}
throw new ArgumentException($"Given object {typeof(TModel).Name} does not have the base implementation type of: {baseType.Name}", nameof(TModel));
}
}

View File

@ -16,10 +16,13 @@ public class AuthorityUser : AuthorityUser<Guid>
}
}
public abstract class AuthorityUser<TKey> where TKey : IEquatable<TKey>
public abstract class AuthorityUser<TKey> : AuthorityUserBase where TKey : IEquatable<TKey>
{
public TKey Id { get; set; }
}
public abstract class AuthorityUserBase
{
public bool Enabled { get; set; }
public bool Confirmed { get; set; }

View File

@ -1,9 +1,9 @@
namespace DotBased.AspNet.Authority.Repositories;
public interface IUserRepository<TUser, TId> where TUser : class where TId : IEquatable<TId>
public interface IUserRepository<TUser> where TUser : class
{
public Task<TUser?> GetUserByIdAsync(TId id);
public Task<TId> GetUserIdAsync(TUser user);
public Task<TUser?> GetUserByIdAsync(string id);
public Task<string> GetUserIdAsync(TUser user);
public Task SetVersion(TUser user, long version);
public Task SetSecurityVersion(TUser user, long version);
}

View File

@ -32,6 +32,7 @@ public class AuthorityManager
public long GenerateVersion() => DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
/// <summary>
/// Protect or unprotect the properties with the <see cref="ProtectAttribute"/>

View File

@ -1,17 +1,24 @@
using DotBased.AspNet.Authority.Crypto;
using DotBased.AspNet.Authority.Models.Validation;
using DotBased.AspNet.Authority.Repositories;
using DotBased.AspNet.Authority.Validators;
using DotBased.Logging;
namespace DotBased.AspNet.Authority.Services;
public class AuthorityUserManager<TUser>
public class AuthorityUserManager<TUser> where TUser : class
{
public AuthorityUserManager(
AuthorityManager manager,
IUserRepository<TUser> userRepository,
IPasswordHasher passwordHasher,
IEnumerable<IPasswordValidator<TUser>>? passwordValidators,
IEnumerable<IUserValidator<TUser>>? userValidators)
{
_logger = LogService.RegisterLogger<AuthorityUserManager<TUser>>();
AuthorityManager = manager;
UserRepository = userRepository;
PasswordHasher = passwordHasher;
if (passwordValidators != null)
PasswordValidators = passwordValidators;
if (userValidators != null)
@ -20,9 +27,24 @@ public class AuthorityUserManager<TUser>
private readonly ILogger _logger;
public AuthorityManager AuthorityManager { get; }
public IUserRepository<TUser> UserRepository { get; }
public IPasswordHasher PasswordHasher { get; }
public IEnumerable<IPasswordValidator<TUser>> PasswordValidators { get; } = [];
public IEnumerable<IUserValidator<TUser>> UserValidators { get; } = [];
public async Task<ValidationResult> ValidatePasswordAsync(TUser user, string password)
{
List<ValidationError> errors = [];
foreach (var validator in PasswordValidators)
{
var validatorResult = await validator.ValidatePasswordAsync(this, user, password);
if (!validatorResult.Success)
{
errors.AddRange(validatorResult.Errors);
}
}
return errors.Count > 0 ? ValidationResult.Failed(errors) : ValidationResult.Ok();
}
}

View File

@ -3,7 +3,7 @@ using DotBased.AspNet.Authority.Services;
namespace DotBased.AspNet.Authority.Validators;
public interface IPasswordValidator<TUser>
public interface IPasswordValidator<TUser> where TUser : class
{
public Task<ValidationResult> ValidatePasswordAsync(AuthorityUserManager<TUser> userManager, string password);
public Task<ValidationResult> ValidatePasswordAsync(AuthorityUserManager<TUser> userManager, TUser user, string password);
}

View File

@ -0,0 +1,27 @@
using DotBased.AspNet.Authority.Models.Authority;
using DotBased.AspNet.Authority.Models.Validation;
using DotBased.AspNet.Authority.Services;
namespace DotBased.AspNet.Authority.Validators;
public class PasswordEqualsValidator<TUser> : IPasswordValidator<TUser> where TUser : class
{
private const string ValidatorId = "Authority.Validator.Password.Equals";
private const string ValidationBase = "Authority.Validation.Password";
public async Task<ValidationResult> ValidatePasswordAsync(AuthorityUserManager<TUser> userManager, TUser user, string password)
{
if (user == null || user is not AuthorityUserBase authorityUser)
{
throw new ArgumentException("Invalid user given!", nameof(user));
}
List<ValidationError> errors = [];
var hashedPassword = await userManager.PasswordHasher.HashPasswordAsync(password);
if (authorityUser.PasswordHash != null && authorityUser.PasswordHash.Equals(hashedPassword, StringComparison.Ordinal))
{
errors.Add(new ValidationError(ValidatorId, $"{ValidationBase}.InUse", "User uses this password already!"));
}
return errors.Count > 0 ? ValidationResult.Failed(errors) : ValidationResult.Ok();
}
}

View File

@ -8,12 +8,12 @@ namespace DotBased.AspNet.Authority.Validators;
/// Validates the password against the options that is configured.
/// </summary>
/// <typeparam name="TUser">The user model used.</typeparam>
public class PasswordOptionsValidator<TUser> : IPasswordValidator<TUser>
public class PasswordOptionsValidator<TUser> : IPasswordValidator<TUser> where TUser : class
{
private const string ValidatorId = "Authority.Validator.Password.Options";
private const string ValidationBase = "Authority.Validation.Password";
public async Task<ValidationResult> ValidatePasswordAsync(AuthorityUserManager<TUser> userManager, string password)
public async Task<ValidationResult> ValidatePasswordAsync(AuthorityUserManager<TUser> userManager, TUser user, string password)
{
if (userManager == null)
{