Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/build-and-deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
7 changes: 1 addition & 6 deletions Directory.Build.props
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,7 @@
<Owners>Michael Vivet</Owners>
<Product>$(ProjectName)</Product>
<Summary>Reusable libraries for building .NET microservice applications</Summary>
<Description>
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.
</Description>
<Description>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.</Description>
<PackageReleaseNotes>
- .NET 10 support.
- Comprehensive rewrite with performance optimizations, improvements, and bug fixes.
Expand Down
47 changes: 37 additions & 10 deletions Nano.App.Api/Mvc/Authentication/AuthJwtRepository.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,42 @@
namespace Nano.App.Api.Mvc.Authentication;

/// <inheritdoc />
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;

/// <summary>
/// Initializes a new instance of the <see cref="AuthJwtRepository"/> class, loading the
/// RSA public key (and private key, if configured) used to validate and sign JWTs.
/// </summary>
/// <param name="options">The JWT authentication options, including the RSA public/private keys, issuer, and audience.</param>
/// <exception cref="ArgumentNullException"><paramref name="options"/> is <see langword="null"/>.</exception>
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();
}

/// <summary>
/// Releases the unmanaged RSA key handles held by the public and, if present, private <see cref="RsaSecurityKey"/> instances used for JWT signing and validation.
/// </summary>
public void Dispose()
{
this.rsaPublicSecurityKey.Rsa?
.Dispose();

this.rsaPrivateSecurityKey?.Rsa?
.Dispose();
}

/// <inheritdoc />
public virtual AccessToken GenerateJwtToken(GenerateJwtToken generateJwtToken)
Expand All @@ -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()
Expand Down Expand Up @@ -78,9 +108,6 @@ public virtual RefreshToken GenerateJwtRefreshToken()
/// <inheritdoc />
public virtual void ValidateTokenForRefresh(string refreshToken)
{
var rsaSecurityKey = this.options.PublicKey
.CreatePublicRsaSecurityKey();

var validationParameters = new TokenValidationParameters
{
ValidateIssuer = true,
Expand All @@ -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)
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Comment thread
vivet marked this conversation as resolved.
Dismissed

rsaAlgorithm
.ImportRSAPublicKey(base64, out _);
Expand All @@ -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();
Comment thread
vivet marked this conversation as resolved.
Dismissed

rsaAlgorithm
.ImportRSAPrivateKey(base64, out _);
Expand Down
Loading