deleting password

This commit is contained in:
john 2025-07-19 14:10:01 +02:00
parent 36d8cc9a4d
commit 2519fc77d2
15 changed files with 237 additions and 47 deletions

View file

@ -11,7 +11,7 @@ namespace Femto.Modules.Auth.Application;
internal class AuthService(
AuthContext context,
SessionStorage storage,
SessionStorage sessionStorage,
IDbConnectionFactory connectionFactory
) : IAuthService
{
@ -33,7 +33,7 @@ internal class AuthService(
var session = new Session(user.Id, true);
await storage.AddSession(session);
await sessionStorage.AddSession(session);
return new(
new UserInfo(user.Id, user.Username, user.Roles.Select(r => r.Role).ToList()),
@ -53,7 +53,7 @@ internal class AuthService(
{
var session = new Session(userId, true);
await storage.AddSession(session);
await sessionStorage.AddSession(session);
return session;
}
@ -62,19 +62,19 @@ internal class AuthService(
{
var session = new Session(userId, false);
await storage.AddSession(session);
await sessionStorage.AddSession(session);
return session;
}
public Task<Session?> GetSession(string sessionId)
{
return storage.GetSession(sessionId);
return sessionStorage.GetSession(sessionId);
}
public async Task DeleteSession(string sessionId)
{
await storage.DeleteSession(sessionId);
await sessionStorage.DeleteSession(sessionId);
}
public async Task<UserAndSession> CreateUserWithCredentials(
@ -113,7 +113,7 @@ internal class AuthService(
var session = new Session(user.Id, true);
await storage.AddSession(session);
await sessionStorage.AddSession(session);
await context.SaveChangesAsync(cancellationToken);
@ -189,7 +189,7 @@ internal class AuthService(
if (token is null)
return (null, null);
if (!token.Validate(rememberMeToken.Verifier))
if (!token.CheckVerifier(rememberMeToken.Verifier))
return (null, null);
var user = await context.Users.SingleOrDefaultAsync(u => u.Id == token.UserId);
@ -218,13 +218,34 @@ internal class AuthService(
if (session is null)
return;
if (!session.Validate(rememberMeToken.Verifier))
if (!session.CheckVerifier(rememberMeToken.Verifier))
return;
context.Remove(session);
await context.SaveChangesAsync();
}
public async Task ChangePassword(Guid userId, string password, CancellationToken cancellationToken)
{
// change the password
// invalidate long term sessions
// invalidate sessions
var user = await context.Users.SingleOrDefaultAsync(u => u.Id == userId,cancellationToken);
if (user is null)
throw new DomainError("invalid user");
user.SetPassword(password);
await context.SaveChangesAsync(cancellationToken);
}
public async Task InvalidateUserSessions(Guid userId, CancellationToken cancellationToken)
{
await sessionStorage.InvalidateUserSessions(userId);
}
private class GetSignupCodesQueryResultRow
{
public string Code { get; set; }

View file

@ -20,13 +20,14 @@ public static class AuthStartup
this IServiceCollection rootContainer,
string connectionString,
IEventBus eventBus,
ILoggerFactory loggerFactory
ILoggerFactory loggerFactory,
TimeProvider timeProvider
)
{
var hostBuilder = Host.CreateDefaultBuilder();
hostBuilder.ConfigureServices(services =>
ConfigureServices(services, connectionString, eventBus, loggerFactory)
ConfigureServices(services, connectionString, eventBus, loggerFactory, timeProvider)
);
var host = hostBuilder.Build();
@ -52,9 +53,12 @@ public static class AuthStartup
IServiceCollection services,
string connectionString,
IEventPublisher publisher,
ILoggerFactory loggerFactory
ILoggerFactory loggerFactory,
TimeProvider timeProvider
)
{
services.AddSingleton(timeProvider);
services.AddTransient<IDbConnectionFactory>(_ => new DbConnectionFactory(connectionString));
services.AddDbContext<AuthContext>(builder =>
@ -83,11 +87,8 @@ public static class AuthStartup
services.AddSingleton(publisher);
services.AddSingleton<SessionStorage>();
services.AddScoped(
typeof(IPipelineBehavior<,>),
typeof(SaveChangesPipelineBehaviour<,>)
);
services.AddScoped(typeof(IPipelineBehavior<,>), typeof(SaveChangesPipelineBehaviour<,>));
services.AddScoped<IAuthService, AuthService>();
}

View file

@ -3,12 +3,6 @@ using Femto.Modules.Auth.Models;
namespace Femto.Modules.Auth.Application;
/// <summary>
/// I broke off IAuthService from IAuthModule because the CQRS distinction is cumbersome when doing auth handling,
/// particularly in regards to session management. I may or may not bother to move the commands and queries here also,
/// but for controller actions I do quite like having the abstraction, and there is less drive within me to bother.
/// It just seems redundant to expose them both, and it's a bit confusin'
/// </summary>
public interface IAuthService
{
public Task<UserAndSession?> AuthenticateUserCredentials(
@ -43,6 +37,9 @@ public interface IAuthService
Task<NewRememberMeToken> CreateRememberMeToken(Guid userId);
Task<(UserInfo?, NewRememberMeToken?)> GetUserWithRememberMeToken(RememberMeToken rememberMeToken);
Task DeleteRememberMeToken(RememberMeToken rememberMeToken);
Task ChangePassword(Guid userId, string password, CancellationToken cancellationToken = default);
Task InvalidateUserSessions(Guid userId, CancellationToken cancellationToken = default);
}
public record UserAndSession(UserInfo User, Session Session);