Initial commit
This commit is contained in:
43
MealPlan.Api/Services/InMemoryRefreshTokenStore.cs
Normal file
43
MealPlan.Api/Services/InMemoryRefreshTokenStore.cs
Normal file
@@ -0,0 +1,43 @@
|
||||
using System.Collections.Concurrent;
|
||||
using MealPlan.Api.Models;
|
||||
|
||||
namespace MealPlan.Api.Services;
|
||||
|
||||
/// <summary>
|
||||
/// Thread-safe in-memory refresh token store registered as a singleton.
|
||||
/// Note: tokens live only for the lifetime of the process. For multi-instance
|
||||
/// deployments this should be swapped for a shared store (e.g. Redis), but it
|
||||
/// satisfies the "do not modify the database" constraint of this project.
|
||||
/// </summary>
|
||||
public class InMemoryRefreshTokenStore : IRefreshTokenStore
|
||||
{
|
||||
private readonly ConcurrentDictionary<string, RefreshToken> _tokens = new();
|
||||
|
||||
public void Add(RefreshToken token) => _tokens[token.Token] = token;
|
||||
|
||||
public RefreshToken? Get(string token) =>
|
||||
_tokens.TryGetValue(token, out var found) ? found : null;
|
||||
|
||||
public RefreshToken? Revoke(string token)
|
||||
{
|
||||
if (!_tokens.TryGetValue(token, out var found))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var wasActive = found.IsActive;
|
||||
found.IsRevoked = true;
|
||||
return wasActive ? found : null;
|
||||
}
|
||||
|
||||
public void RemoveExpired()
|
||||
{
|
||||
foreach (var kvp in _tokens)
|
||||
{
|
||||
if (kvp.Value.IsRevoked || DateTime.UtcNow >= kvp.Value.ExpiresAtUtc)
|
||||
{
|
||||
_tokens.TryRemove(kvp.Key, out _);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user