feat/ImproveRoles #4

Merged
ChiaraBm merged 4 commits from feat/ImproveRoles into v2.1 2026-01-16 12:08:41 +00:00
3 changed files with 50 additions and 9 deletions
Showing only changes of commit bee381702b - Show all commits

View File

@@ -0,0 +1,6 @@
namespace Moonlight.Api.Configuration;
public class SessionOptions
{
public int ValidationCacheMinutes { get; set; } = 3;
}

View File

@@ -1,6 +1,9 @@
using System.Security.Claims; using System.Security.Claims;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Caching.Memory;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Moonlight.Api.Configuration;
using Moonlight.Api.Database; using Moonlight.Api.Database;
using Moonlight.Api.Database.Entities; using Moonlight.Api.Database.Entities;
@@ -9,15 +12,22 @@ namespace Moonlight.Api.Services;
public class UserAuthService public class UserAuthService
{ {
private readonly DatabaseRepository<User> UserRepository; private readonly DatabaseRepository<User> UserRepository;
private readonly IMemoryCache Cache;
private readonly ILogger<UserAuthService> Logger; private readonly ILogger<UserAuthService> Logger;
private readonly IOptions<SessionOptions> Options;
private const string UserIdClaim = "UserId"; private const string UserIdClaim = "UserId";
private const string IssuedAtClaim = "IssuedAt"; private const string IssuedAtClaim = "IssuedAt";
public UserAuthService(DatabaseRepository<User> userRepository, ILogger<UserAuthService> logger) public UserAuthService(
DatabaseRepository<User> userRepository,
ILogger<UserAuthService> logger,
IMemoryCache cache, IOptions<SessionOptions> options)
{ {
UserRepository = userRepository; UserRepository = userRepository;
Logger = logger; Logger = logger;
Cache = cache;
Options = options;
} }
public async Task<bool> SyncAsync(ClaimsPrincipal? principal) public async Task<bool> SyncAsync(ClaimsPrincipal? principal)
@@ -75,13 +85,31 @@ public class UserAuthService
if (!int.TryParse(userIdString, out var userId)) if (!int.TryParse(userIdString, out var userId))
return false; return false;
var user = await UserRepository var cacheKey = $"Moonlight.{nameof(UserAuthService)}.{nameof(ValidateAsync)}-{userId}";
.Query()
.AsNoTracking()
.FirstOrDefaultAsync(user => user.Id == userId);
if (user == null) if (!Cache.TryGetValue<UserSession>(cacheKey, out var user))
return false; {
user = await UserRepository
.Query()
.AsNoTracking()
.Where(u => u.Id == userId)
.Select(u => new UserSession(u.InvalidateTimestamp))
.FirstOrDefaultAsync();
if (user == null)
return false;
Cache.Set(
cacheKey,
user,
TimeSpan.FromMinutes(Options.Value.ValidationCacheMinutes)
);
}
else
{
if (user == null)
return false;
}
var issuedAtString = principal.FindFirstValue(IssuedAtClaim); var issuedAtString = principal.FindFirstValue(IssuedAtClaim);
@@ -90,10 +118,14 @@ public class UserAuthService
var issuedAt = DateTimeOffset.FromUnixTimeSeconds(issuedAtUnix).ToUniversalTime(); var issuedAt = DateTimeOffset.FromUnixTimeSeconds(issuedAtUnix).ToUniversalTime();
// If the issued at timestamp is greater than the token validation timestamp // If the issued at timestamp is greater than the token validation timestamp,
// everything is fine. If not it means that the token should be invalidated // everything is fine. If not, it means that the token should be invalidated
// as it is too old // as it is too old
return issuedAt > user.InvalidateTimestamp; return issuedAt > user.InvalidateTimestamp;
} }
// A small model which contains data queried per session validation after the defined cache time.
// Used for projection
private record UserSession(DateTimeOffset InvalidateTimestamp);
} }

View File

@@ -29,6 +29,9 @@ public partial class Startup
builder.Services.AddSingleton<DiagnoseService>(); builder.Services.AddSingleton<DiagnoseService>();
builder.Services.AddSingleton<IDiagnoseProvider, UpdateDiagnoseProvider>(); builder.Services.AddSingleton<IDiagnoseProvider, UpdateDiagnoseProvider>();
builder.Services.AddMemoryCache();
builder.Services.AddOptions<SessionOptions>().BindConfiguration("Moonlight:Session");
} }
private static void UseBase(WebApplication application) private static void UseBase(WebApplication application)