diff --git a/.github/workflows/build-and-deploy.yml b/.github/workflows/build-and-deploy.yml
index cb36b2cd..0729f08f 100644
--- a/.github/workflows/build-and-deploy.yml
+++ b/.github/workflows/build-and-deploy.yml
@@ -8,7 +8,7 @@ on:
- master
env:
APP_NAME: Nano.Library
- VERSION: 10.0.0-rc2
+ VERSION: 10.0.0-rc3
jobs:
build-and-deploy:
runs-on: windows-latest
diff --git a/Directory.Build.props b/Directory.Build.props
index 73a56341..02d308da 100644
--- a/Directory.Build.props
+++ b/Directory.Build.props
@@ -22,12 +22,7 @@
Michael Vivet
$(ProjectName)
Reusable libraries for building .NET microservice applications
-
- This package is part of the Nano Library, a set of reusable .NET libraries for building microservice applications.
- Nano addresses common non-business concerns such as logging, persistence, messaging, validation, and documentation,
- while remaining fully configurable and extensible, so applications can stay focused on business logic.
- See https://github.com/Nano-Core/Nano.Library for details.
-
+ This package is part of the Nano Library, a set of reusable .NET libraries for building microservice applications. Nano addresses common non-business concerns such as logging, persistence, messaging, validation, and documentation, while remaining fully configurable and extensible, so applications can stay focused on business logic. See https://github.com/Nano-Core/Nano.Library for details.
- .NET 10 support.
- Comprehensive rewrite with performance optimizations, improvements, and bug fixes.
diff --git a/Nano.App.Api/Mvc/Authentication/AuthJwtRepository.cs b/Nano.App.Api/Mvc/Authentication/AuthJwtRepository.cs
index e579a9d1..c31e9935 100644
--- a/Nano.App.Api/Mvc/Authentication/AuthJwtRepository.cs
+++ b/Nano.App.Api/Mvc/Authentication/AuthJwtRepository.cs
@@ -15,9 +15,42 @@
namespace Nano.App.Api.Mvc.Authentication;
///
-public class AuthJwtRepository(JwtAuthenticationOptions options) : IAuthJwtRepository
+public class AuthJwtRepository : IAuthJwtRepository
{
- private readonly JwtAuthenticationOptions options = options ?? throw new ArgumentNullException(nameof(options));
+ private readonly JwtAuthenticationOptions options;
+ private readonly RsaSecurityKey rsaPublicSecurityKey;
+ private readonly RsaSecurityKey? rsaPrivateSecurityKey;
+
+ ///
+ /// Initializes a new instance of the class, loading the
+ /// RSA public key (and private key, if configured) used to validate and sign JWTs.
+ ///
+ /// The JWT authentication options, including the RSA public/private keys, issuer, and audience.
+ /// is .
+ public AuthJwtRepository(JwtAuthenticationOptions options)
+ {
+ ArgumentNullException.ThrowIfNull(options);
+
+ this.options = options ?? throw new ArgumentNullException(nameof(options));
+
+ this.rsaPublicSecurityKey = this.options.PublicKey
+ .CreatePublicRsaSecurityKey();
+
+ this.rsaPrivateSecurityKey = this.options.PrivateKey?
+ .CreatePrivateRsaSecurityKey();
+ }
+
+ ///
+ /// Releases the unmanaged RSA key handles held by the public and, if present, private instances used for JWT signing and validation.
+ ///
+ public void Dispose()
+ {
+ this.rsaPublicSecurityKey.Rsa?
+ .Dispose();
+
+ this.rsaPrivateSecurityKey?.Rsa?
+ .Dispose();
+ }
///
public virtual AccessToken GenerateJwtToken(GenerateJwtToken generateJwtToken)
@@ -43,10 +76,7 @@ public virtual AccessToken GenerateJwtToken(GenerateJwtToken generateJwtToken)
var notBeforeAt = DateTimeOffset.UtcNow;
var expireAt = DateTimeOffset.UtcNow.Add(this.options.Expiration);
- var rsaSecurityKey = this.options.PrivateKey?
- .CreatePrivateRsaSecurityKey();
-
- var signingCredentials = new SigningCredentials(rsaSecurityKey, SecurityAlgorithms.RsaSha512);
+ var signingCredentials = new SigningCredentials(this.rsaPrivateSecurityKey, SecurityAlgorithms.RsaSha512);
var securityToken = new JwtSecurityToken(this.options.Issuer, this.options.Audience, claims, notBeforeAt.DateTime, expireAt.DateTime, signingCredentials);
var token = new JwtSecurityTokenHandler()
@@ -78,9 +108,6 @@ public virtual RefreshToken GenerateJwtRefreshToken()
///
public virtual void ValidateTokenForRefresh(string refreshToken)
{
- var rsaSecurityKey = this.options.PublicKey
- .CreatePublicRsaSecurityKey();
-
var validationParameters = new TokenValidationParameters
{
ValidateIssuer = true,
@@ -89,7 +116,7 @@ public virtual void ValidateTokenForRefresh(string refreshToken)
ValidateIssuerSigningKey = true,
ValidIssuer = this.options.Issuer,
ValidAudience = this.options.Audience,
- IssuerSigningKey = rsaSecurityKey,
+ IssuerSigningKey = this.rsaPublicSecurityKey,
ClockSkew = TimeSpan.FromMinutes(5)
};
diff --git a/Nano.App.Api/Mvc/Authentication/Extensions/StringExtensions.cs b/Nano.App.Api/Mvc/Authentication/Extensions/StringExtensions.cs
index 547b6b2a..7d864f71 100644
--- a/Nano.App.Api/Mvc/Authentication/Extensions/StringExtensions.cs
+++ b/Nano.App.Api/Mvc/Authentication/Extensions/StringExtensions.cs
@@ -12,7 +12,7 @@ internal static RsaSecurityKey CreatePublicRsaSecurityKey(this string key)
var base64 = Convert.FromBase64String(key);
- using var rsaAlgorithm = RSA.Create();
+ var rsaAlgorithm = RSA.Create();
rsaAlgorithm
.ImportRSAPublicKey(base64, out _);
@@ -26,7 +26,7 @@ internal static RsaSecurityKey CreatePrivateRsaSecurityKey(this string key)
var base64 = Convert.FromBase64String(key);
- using var rsaAlgorithm = RSA.Create();
+ var rsaAlgorithm = RSA.Create();
rsaAlgorithm
.ImportRSAPrivateKey(base64, out _);