Implemented user logout and deletion service. Added Auth, Deletion and Logout hook. Restructed controllers

This commit is contained in:
2026-02-01 16:26:11 +01:00
parent c8fe11bd2b
commit 58c882603c
11 changed files with 258 additions and 65 deletions

View File

@@ -6,6 +6,7 @@ using Microsoft.Extensions.Options;
using Moonlight.Api.Configuration;
using Moonlight.Api.Database;
using Moonlight.Api.Database.Entities;
using Moonlight.Api.Interfaces;
using Moonlight.Shared;
namespace Moonlight.Api.Services;
@@ -16,21 +17,25 @@ public class UserAuthService
private readonly IMemoryCache Cache;
private readonly ILogger<UserAuthService> Logger;
private readonly IOptions<SessionOptions> Options;
private readonly IEnumerable<IUserAuthHook> Hooks;
private const string UserIdClaim = "UserId";
private const string IssuedAtClaim = "IssuedAt";
public const string CacheKeyPattern = $"Moonlight.{nameof(UserAuthService)}.{nameof(ValidateAsync)}-{{0}}";
public UserAuthService(
DatabaseRepository<User> userRepository,
ILogger<UserAuthService> logger,
IMemoryCache cache, IOptions<SessionOptions> options)
IMemoryCache cache, IOptions<SessionOptions> options,
IEnumerable<IUserAuthHook> hooks
)
{
UserRepository = userRepository;
Logger = logger;
Cache = cache;
Options = options;
Hooks = hooks;
}
public async Task<bool> SyncAsync(ClaimsPrincipal? principal)
@@ -50,7 +55,6 @@ public class UserAuthService
// We use email as the primary identifier here
var user = await UserRepository
.Query()
.AsNoTracking()
.FirstOrDefaultAsync(user => user.Email == email);
if (user == null) // Sync user if not already existing in the database
@@ -74,6 +78,13 @@ public class UserAuthService
new Claim(IssuedAtClaim, DateTimeOffset.UtcNow.ToUnixTimeSeconds().ToString())
]);
foreach (var hook in Hooks)
{
// Run every hook and if any returns false we return false as well
if(!await hook.SyncAsync(principal, user))
return false;
}
return true;
}
@@ -89,7 +100,7 @@ public class UserAuthService
return false;
var cacheKey = string.Format(CacheKeyPattern, userId);
if (!Cache.TryGetValue<UserSession>(cacheKey, out var user))
{
user = await UserRepository
@@ -131,9 +142,17 @@ public class UserAuthService
if (issuedAt < user.InvalidateTimestamp)
return false;
// Load every permission as claim
principal.Identities.First().AddClaims(
user.Permissions.Select(x => new Claim(Permissions.ClaimType, x))
);
foreach (var hook in Hooks)
{
// Run every hook and if any returns false we return false as well
if(!await hook.ValidateAsync(principal, userId))
return false;
}
return true;
}