diff --git a/src/FiscalOS.Core/Identity/IPasswordHasher.cs b/src/FiscalOS.Core/Identity/IPasswordHasher.cs deleted file mode 100644 index 280ab67..0000000 --- a/src/FiscalOS.Core/Identity/IPasswordHasher.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace FiscalOS.Core.Identity; - -public interface IPasswordHasher -{ - string Hash(string password); - bool Verify(string providedPassword, string hashedPassword); -} \ No newline at end of file diff --git a/src/FiscalOS.API/Login/JwtOptions.cs b/src/FiscalOS.Infra/Authentication/JwtOptions.cs similarity index 75% rename from src/FiscalOS.API/Login/JwtOptions.cs rename to src/FiscalOS.Infra/Authentication/JwtOptions.cs index 63323fe..1ee9187 100644 --- a/src/FiscalOS.API/Login/JwtOptions.cs +++ b/src/FiscalOS.Infra/Authentication/JwtOptions.cs @@ -1,8 +1,6 @@ -using Microsoft.Extensions.Options; +namespace FiscalOS.Infra.Authentication; -namespace FiscalOS.API.Login; - -internal sealed record JwtOptions +public sealed record JwtOptions { public string Issuer { get; init; } = string.Empty; public string Audience { get; init; } = string.Empty; @@ -10,7 +8,7 @@ internal sealed record JwtOptions public int ExpiryInMinutes { get; init; } = 5; } -internal sealed record JwtOptionsSetup : IConfigureOptions +public sealed record JwtOptionsSetup : IConfigureOptions { private const string SectionName = nameof(JwtOptions); private readonly IConfiguration _configuration; diff --git a/src/FiscalOS.Infra/Identity/PasswordHasher.cs b/src/FiscalOS.Infra/Authentication/PasswordHasher.cs similarity index 90% rename from src/FiscalOS.Infra/Identity/PasswordHasher.cs rename to src/FiscalOS.Infra/Authentication/PasswordHasher.cs index 8ebd890..42e996f 100644 --- a/src/FiscalOS.Infra/Identity/PasswordHasher.cs +++ b/src/FiscalOS.Infra/Authentication/PasswordHasher.cs @@ -1,4 +1,4 @@ -namespace FiscalOS.Infra.Identity; +namespace FiscalOS.Infra.Authentication; public sealed class PasswordHasher : IPasswordHasher { @@ -17,6 +17,11 @@ public sealed class PasswordHasher : IPasswordHasher return new(); } + public static PasswordHasher From(IServiceProvider serviceProvider) + { + return new(); + } + public string Hash(string password) { var salt = RandomNumberGenerator.GetBytes(SaltSize); diff --git a/src/FiscalOS.API/Login/TokenService.cs b/src/FiscalOS.Infra/Authentication/TokenGenerator.cs similarity index 54% rename from src/FiscalOS.API/Login/TokenService.cs rename to src/FiscalOS.Infra/Authentication/TokenGenerator.cs index f4d736f..5310a0b 100644 --- a/src/FiscalOS.API/Login/TokenService.cs +++ b/src/FiscalOS.Infra/Authentication/TokenGenerator.cs @@ -1,30 +1,41 @@ -using System.IdentityModel.Tokens.Jwt; -using System.Security.Claims; -using System.Security.Cryptography; -using System.Text; +namespace FiscalOS.Infra.Authentication; -using FiscalOS.Core.Identity; - -using Microsoft.Extensions.Options; -using Microsoft.IdentityModel.Tokens; - -namespace FiscalOS.API.Login; - -internal sealed class TokenService( - TimeProvider timeProvider, - IOptions jwtOptions -) +public sealed class TokenGenerator : ITokenGenerator { private const int RefreshTokenExpiryInHours = 12; - private readonly JwtOptions _jwtOptions = jwtOptions.Value; - private readonly TimeProvider _timeProvider = timeProvider; + private readonly IOptions _jwtOptions; + private readonly TimeProvider _timeProvider; + + private TokenGenerator( + TimeProvider timeProvider, + IOptions jwtOptions + ) + { + _timeProvider = timeProvider; + _jwtOptions = jwtOptions; + } + + public static TokenGenerator From(IServiceProvider serviceProvider) + { + var timeProvider = serviceProvider.GetRequiredService(); + var jwtOptions = serviceProvider.GetRequiredService>(); + return new(timeProvider, jwtOptions); + } + + public static TokenGenerator From( + TimeProvider timeProvider, + IOptions jwtOptions + ) + { + return new(timeProvider, jwtOptions); + } public string GenerateAccessToken(User user) { var tokenHandler = new JwtSecurityTokenHandler(); - var secretKeyBytes = Encoding.UTF8.GetBytes(_jwtOptions.Secret); + var secretKeyBytes = Encoding.UTF8.GetBytes(_jwtOptions.Value.Secret); var issuedAt = _timeProvider.GetUtcNow(); - var expiresAt = issuedAt.AddMinutes(_jwtOptions.ExpiryInMinutes); + var expiresAt = issuedAt.AddMinutes(_jwtOptions.Value.ExpiryInMinutes); List claims = [ new(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()), new(JwtRegisteredClaimNames.Sub, user.Id.ToString()), @@ -35,8 +46,8 @@ internal sealed class TokenService( Subject = new(claims), IssuedAt = issuedAt.UtcDateTime, Expires = expiresAt.UtcDateTime, - Issuer = _jwtOptions.Issuer, - Audience = _jwtOptions.Audience, + Issuer = _jwtOptions.Value.Issuer, + Audience = _jwtOptions.Value.Audience, SigningCredentials = new( new SymmetricSecurityKey(secretKeyBytes), SecurityAlgorithms.HmacSha256Signature @@ -64,4 +75,4 @@ internal sealed class TokenService( var token = Convert.ToBase64String(randomBytes); return token; } -} +} \ No newline at end of file diff --git a/src/FiscalOS.Infra/FiscalOS.Infra.csproj b/src/FiscalOS.Infra/FiscalOS.Infra.csproj index 9e6e2de..877c74d 100644 --- a/src/FiscalOS.Infra/FiscalOS.Infra.csproj +++ b/src/FiscalOS.Infra/FiscalOS.Infra.csproj @@ -1,6 +1,7 @@  + diff --git a/src/FiscalOS.Infra/Usings.cs b/src/FiscalOS.Infra/Usings.cs index 3910b7f..a462788 100644 --- a/src/FiscalOS.Infra/Usings.cs +++ b/src/FiscalOS.Infra/Usings.cs @@ -1,8 +1,12 @@ +global using System.IdentityModel.Tokens.Jwt; +global using System.Security.Claims; global using System.Security.Cryptography; +global using System.Text; +global using FiscalOS.Core.Authentication; global using FiscalOS.Core.Identity; +global using FiscalOS.Infra.Authentication; global using FiscalOS.Infra.Data; -global using FiscalOS.Infra.Identity; global using Microsoft.EntityFrameworkCore; global using Microsoft.EntityFrameworkCore.Diagnostics; @@ -10,4 +14,5 @@ global using Microsoft.Extensions.Configuration; global using Microsoft.Extensions.DependencyInjection; global using Microsoft.Extensions.Hosting; global using Microsoft.Extensions.Logging; -global using Microsoft.Extensions.Options; \ No newline at end of file +global using Microsoft.Extensions.Options; +global using Microsoft.IdentityModel.Tokens; \ No newline at end of file