-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Refactor JWT handling and introduce token creation classes
Updated ServiceCollectionExtensions.cs to use a new GetJwtSettings method for retrieving JWT settings, improving code readability and maintainability. Registered a new ITokenProvider service and updated JWT bearer authentication setup. Added ClaimBuilder.cs with a fluent API for building claims. Introduced ConfigurationExtensions.cs with GetJwtSettings method for retrieving and validating JWT settings. Added JwtSettings.cs to represent JWT settings. Introduced ITokenProvider.cs interface for creating tokens with customizable claims. Added JwtTokenProvider.cs implementing ITokenProvider, using JwtSettings and ClaimBuilder for token creation.
- Loading branch information
Showing
6 changed files
with
149 additions
and
13 deletions.
There are no files selected for viewing
53 changes: 53 additions & 0 deletions
53
Sources/EasyExtensions.Authorization/Builders/ClaimBuilder.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
using System; | ||
using System.Security.Claims; | ||
using System.Collections.Generic; | ||
|
||
namespace EasyExtensions.Authorization.Builders | ||
{ | ||
/// <summary> | ||
/// Claim builder. | ||
/// </summary> | ||
public class ClaimBuilder | ||
{ | ||
private readonly List<Claim> _claims = []; | ||
|
||
/// <summary> | ||
/// Adds a claim to the builder. | ||
/// </summary> | ||
/// <param name="type"> Claim type. </param> | ||
/// <param name="value"> Claim value. </param> | ||
/// <returns> Current <see cref="ClaimBuilder"/> instance. </returns> | ||
/// <exception cref="ArgumentException"> When <paramref name="type"/> or <paramref name="value"/> is null or empty. </exception> | ||
public ClaimBuilder Add(string type, string value) | ||
{ | ||
ArgumentException.ThrowIfNullOrWhiteSpace(type, nameof(type)); | ||
ArgumentException.ThrowIfNullOrWhiteSpace(value, nameof(value)); | ||
_claims.Add(new Claim(type, value)); | ||
return this; | ||
} | ||
|
||
/// <summary> | ||
/// Adds a claim to the builder. | ||
/// </summary> | ||
/// <param name="claim"> Claim to add. </param> | ||
/// <returns> Current <see cref="ClaimBuilder"/> instance. </returns> | ||
/// <exception cref="ArgumentNullException"> When <paramref name="claim"/> is null or <see cref="Claim.Type"/> or <see cref="Claim.Value"/> is empty. </exception> | ||
public ClaimBuilder Add(Claim claim) | ||
{ | ||
ArgumentNullException.ThrowIfNull(claim, nameof(claim)); | ||
ArgumentNullException.ThrowIfNull(claim.Type, nameof(claim.Type)); | ||
ArgumentNullException.ThrowIfNull(claim.Value, nameof(claim.Value)); | ||
_claims.Add(claim); | ||
return this; | ||
} | ||
|
||
/// <summary> | ||
/// Builds the claims. | ||
/// </summary> | ||
/// <returns> Array of claims. </returns> | ||
public Claim[] Build() | ||
{ | ||
return [.. _claims]; | ||
} | ||
} | ||
} |
28 changes: 28 additions & 0 deletions
28
Sources/EasyExtensions.Authorization/Extensions/ConfigurationExtensions.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
using System; | ||
using System.Collections.Generic; | ||
using Microsoft.Extensions.Configuration; | ||
using EasyExtensions.Authorization.Models; | ||
|
||
namespace EasyExtensions.Authorization.Services | ||
{ | ||
internal static class ConfigurationExtensions | ||
{ | ||
internal static JwtSettings GetJwtSettings(this IConfiguration configuration) | ||
{ | ||
var jwtSettings = configuration.GetSection("JwtSettings"); | ||
int lifetimeMinutes = jwtSettings.Exists() ? int.Parse(jwtSettings["LifetimeMinutes"]!) : int.Parse(configuration["JwtLifetimeMinutes"]!); | ||
ArgumentOutOfRangeException.ThrowIfNegativeOrZero(lifetimeMinutes, nameof(lifetimeMinutes)); | ||
|
||
return new JwtSettings | ||
{ | ||
Key = (!jwtSettings.Exists() ? configuration["JwtKey"] : jwtSettings["Key"]) | ||
?? throw new KeyNotFoundException("JwtSettings.Key or JwtKey is not set"), | ||
Issuer = (!jwtSettings.Exists() ? configuration["JwtIssuer"] : jwtSettings["Issuer"]) | ||
?? throw new KeyNotFoundException("JwtSettings.Issuer or JwtIssuer is not set"), | ||
Audience = (!jwtSettings.Exists() ? configuration["JwtAudience"] : jwtSettings["Audience"]) | ||
?? throw new KeyNotFoundException("JwtSettings.Audience or JwtAudience is not set"), | ||
LifetimeMinutes = lifetimeMinutes | ||
}; | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
10 changes: 10 additions & 0 deletions
10
Sources/EasyExtensions.Authorization/Models/JwtSettings.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
namespace EasyExtensions.Authorization.Models | ||
{ | ||
internal class JwtSettings | ||
{ | ||
internal int? LifetimeMinutes { get; set; } | ||
internal string Key { get; set; } = string.Empty; | ||
internal string Issuer { get; set; } = string.Empty; | ||
internal string Audience { get; set; } = string.Empty; | ||
} | ||
} |
10 changes: 10 additions & 0 deletions
10
Sources/EasyExtensions.Authorization/Services/ITokenProvider.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
using System; | ||
using EasyExtensions.Authorization.Builders; | ||
|
||
namespace EasyExtensions.Authorization.Services | ||
{ | ||
internal interface ITokenProvider | ||
{ | ||
string CreateToken(Func<ClaimBuilder, ClaimBuilder>? claimBuilder = null); | ||
} | ||
} |
42 changes: 42 additions & 0 deletions
42
Sources/EasyExtensions.Authorization/Services/JwtTokenProvider.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
using System; | ||
using System.Text; | ||
using Microsoft.IdentityModel.Tokens; | ||
using System.IdentityModel.Tokens.Jwt; | ||
using Microsoft.Extensions.Configuration; | ||
using EasyExtensions.Authorization.Models; | ||
using EasyExtensions.Authorization.Builders; | ||
|
||
namespace EasyExtensions.Authorization.Services | ||
{ | ||
internal class JwtTokenProvider(IConfiguration _configuration) : ITokenProvider | ||
{ | ||
private readonly JwtSettings _jwtSettings = _configuration.GetJwtSettings(); | ||
|
||
public string CreateToken(Func<ClaimBuilder, ClaimBuilder>? claimBuilder = null) | ||
{ | ||
var claims = claimBuilder == null ? [] : claimBuilder(new ClaimBuilder()).Build(); | ||
var securityKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_jwtSettings.Key)); | ||
#pragma warning disable CA2208 // Instantiate argument exceptions correctly | ||
string algorithm = _jwtSettings.Key.Length switch | ||
{ | ||
128 / 8 => SecurityAlgorithms.HmacSha256, | ||
192 / 8 => SecurityAlgorithms.HmacSha384, | ||
256 / 8 => SecurityAlgorithms.HmacSha512, | ||
_ => throw new ArgumentOutOfRangeException(nameof(_jwtSettings), "Key length must be 128, 192 or 256 bits"), | ||
}; | ||
#pragma warning restore CA2208 // Instantiate argument exceptions correctly | ||
var credentials = new SigningCredentials(securityKey, algorithm); | ||
var expirationDate = _jwtSettings.LifetimeMinutes.HasValue | ||
? DateTime.UtcNow.AddMinutes(_jwtSettings.LifetimeMinutes.Value) | ||
: DateTime.UtcNow.AddMinutes(30); | ||
var tokenDescriptor = new JwtSecurityToken( | ||
issuer: _jwtSettings.Issuer, | ||
audience: _jwtSettings.Audience, | ||
claims: claims, | ||
expires: expirationDate, | ||
signingCredentials: credentials); | ||
return new JwtSecurityTokenHandler() | ||
.WriteToken(tokenDescriptor); | ||
} | ||
} | ||
} |