feat: implement IAccountResolver interface and MemAccountResolver
Adds the IAccountResolver interface (FetchAsync, StoreAsync, IsReadOnly) and a MemAccountResolver backed by ConcurrentDictionary for in-memory JWT storage in tests and simple operator deployments. Reference: golang/nats-server/server/accounts.go:4035+
This commit is contained in:
65
src/NATS.Server/Auth/Jwt/AccountResolver.cs
Normal file
65
src/NATS.Server/Auth/Jwt/AccountResolver.cs
Normal file
@@ -0,0 +1,65 @@
|
||||
using System.Collections.Concurrent;
|
||||
|
||||
namespace NATS.Server.Auth.Jwt;
|
||||
|
||||
/// <summary>
|
||||
/// Resolves account JWTs by account NKey public key. The server calls
|
||||
/// <see cref="FetchAsync"/> during client authentication to obtain the
|
||||
/// account JWT that was previously published by an account operator.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Reference: golang/nats-server/server/accounts.go:4035+ — AccountResolver interface
|
||||
/// and MemAccResolver implementation.
|
||||
/// </remarks>
|
||||
public interface IAccountResolver
|
||||
{
|
||||
/// <summary>
|
||||
/// Fetches the JWT for the given account NKey. Returns <c>null</c> when
|
||||
/// the NKey is not known to this resolver.
|
||||
/// </summary>
|
||||
Task<string?> FetchAsync(string accountNkey);
|
||||
|
||||
/// <summary>
|
||||
/// Stores (or replaces) the JWT for the given account NKey. Callers that
|
||||
/// target a read-only resolver should check <see cref="IsReadOnly"/> first.
|
||||
/// </summary>
|
||||
Task StoreAsync(string accountNkey, string jwt);
|
||||
|
||||
/// <summary>
|
||||
/// When <c>true</c>, <see cref="StoreAsync"/> is not supported and will
|
||||
/// throw <see cref="NotSupportedException"/>. Directory and URL resolvers
|
||||
/// may be read-only; in-memory resolvers are not.
|
||||
/// </summary>
|
||||
bool IsReadOnly { get; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// In-memory account resolver backed by a <see cref="ConcurrentDictionary{TKey,TValue}"/>.
|
||||
/// Suitable for tests and simple single-operator deployments where account JWTs
|
||||
/// are provided at startup via <see cref="StoreAsync"/>.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Reference: golang/nats-server/server/accounts.go — MemAccResolver
|
||||
/// </remarks>
|
||||
public sealed class MemAccountResolver : IAccountResolver
|
||||
{
|
||||
private readonly ConcurrentDictionary<string, string> _accounts =
|
||||
new(StringComparer.Ordinal);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public bool IsReadOnly => false;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public Task<string?> FetchAsync(string accountNkey)
|
||||
{
|
||||
_accounts.TryGetValue(accountNkey, out var jwt);
|
||||
return Task.FromResult(jwt);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public Task StoreAsync(string accountNkey, string jwt)
|
||||
{
|
||||
_accounts[accountNkey] = jwt;
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user