forked from xiongyuxing/tiku-backend.net
60 lines
1.8 KiB
C#
60 lines
1.8 KiB
C#
using System.Security.Cryptography;
|
|
using Microsoft.Extensions.Options;
|
|
using Microsoft.IdentityModel.Tokens;
|
|
using Tiku.Application.Security;
|
|
|
|
namespace Tiku.Infrastructure.Auth;
|
|
|
|
internal sealed class JwtKeyRing : IJwtKeyRing, IDisposable
|
|
{
|
|
private readonly List<RSA> keys = [];
|
|
|
|
public JwtKeyRing(IOptions<JwtOptions> options)
|
|
{
|
|
var value = options.Value;
|
|
var signingRsa = RSA.Create(3072);
|
|
keys.Add(signingRsa);
|
|
if (!string.IsNullOrWhiteSpace(value.PrivateKeyPem))
|
|
{
|
|
signingRsa.ImportFromPem(value.PrivateKeyPem);
|
|
}
|
|
|
|
var signingKey = CreateKey(signingRsa, value.KeyId);
|
|
SigningCredentials = new SigningCredentials(signingKey, SecurityAlgorithms.RsaSha256);
|
|
|
|
var validationKeys = new List<SecurityKey> { signingKey };
|
|
foreach (var pair in value.PublicKeys.Where(pair => pair.Key != value.KeyId))
|
|
{
|
|
var rsa = RSA.Create();
|
|
rsa.ImportFromPem(pair.Value);
|
|
keys.Add(rsa);
|
|
validationKeys.Add(CreateKey(rsa, pair.Key));
|
|
}
|
|
|
|
ValidationKeys = validationKeys;
|
|
}
|
|
|
|
public SigningCredentials SigningCredentials { get; }
|
|
public IReadOnlyCollection<SecurityKey> ValidationKeys { get; }
|
|
|
|
private static RsaSecurityKey CreateKey(RSA rsa, string keyId) => new(rsa)
|
|
{
|
|
KeyId = keyId,
|
|
// IdentityModel caches signature providers globally by key identity. A key ring owns
|
|
// and disposes its RSA instances, so a provider retained by another in-process host
|
|
// could otherwise reference an RSA instance that has already been disposed.
|
|
CryptoProviderFactory = new CryptoProviderFactory
|
|
{
|
|
CacheSignatureProviders = false
|
|
}
|
|
};
|
|
|
|
public void Dispose()
|
|
{
|
|
foreach (var key in keys)
|
|
{
|
|
key.Dispose();
|
|
}
|
|
}
|
|
}
|