feat(infra): move authentication implementations and add ITokenGenerator
This commit is contained in:
@@ -1,7 +0,0 @@
|
|||||||
namespace FiscalOS.Core.Identity;
|
|
||||||
|
|
||||||
public interface IPasswordHasher
|
|
||||||
{
|
|
||||||
string Hash(string password);
|
|
||||||
bool Verify(string providedPassword, string hashedPassword);
|
|
||||||
}
|
|
||||||
+3
-5
@@ -1,8 +1,6 @@
|
|||||||
using Microsoft.Extensions.Options;
|
namespace FiscalOS.Infra.Authentication;
|
||||||
|
|
||||||
namespace FiscalOS.API.Login;
|
public sealed record JwtOptions
|
||||||
|
|
||||||
internal sealed record JwtOptions
|
|
||||||
{
|
{
|
||||||
public string Issuer { get; init; } = string.Empty;
|
public string Issuer { get; init; } = string.Empty;
|
||||||
public string Audience { 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;
|
public int ExpiryInMinutes { get; init; } = 5;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal sealed record JwtOptionsSetup : IConfigureOptions<JwtOptions>
|
public sealed record JwtOptionsSetup : IConfigureOptions<JwtOptions>
|
||||||
{
|
{
|
||||||
private const string SectionName = nameof(JwtOptions);
|
private const string SectionName = nameof(JwtOptions);
|
||||||
private readonly IConfiguration _configuration;
|
private readonly IConfiguration _configuration;
|
||||||
+6
-1
@@ -1,4 +1,4 @@
|
|||||||
namespace FiscalOS.Infra.Identity;
|
namespace FiscalOS.Infra.Authentication;
|
||||||
|
|
||||||
public sealed class PasswordHasher : IPasswordHasher
|
public sealed class PasswordHasher : IPasswordHasher
|
||||||
{
|
{
|
||||||
@@ -17,6 +17,11 @@ public sealed class PasswordHasher : IPasswordHasher
|
|||||||
return new();
|
return new();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static PasswordHasher From(IServiceProvider serviceProvider)
|
||||||
|
{
|
||||||
|
return new();
|
||||||
|
}
|
||||||
|
|
||||||
public string Hash(string password)
|
public string Hash(string password)
|
||||||
{
|
{
|
||||||
var salt = RandomNumberGenerator.GetBytes(SaltSize);
|
var salt = RandomNumberGenerator.GetBytes(SaltSize);
|
||||||
+33
-22
@@ -1,30 +1,41 @@
|
|||||||
using System.IdentityModel.Tokens.Jwt;
|
namespace FiscalOS.Infra.Authentication;
|
||||||
using System.Security.Claims;
|
|
||||||
using System.Security.Cryptography;
|
|
||||||
using System.Text;
|
|
||||||
|
|
||||||
using FiscalOS.Core.Identity;
|
public sealed class TokenGenerator : ITokenGenerator
|
||||||
|
|
||||||
using Microsoft.Extensions.Options;
|
|
||||||
using Microsoft.IdentityModel.Tokens;
|
|
||||||
|
|
||||||
namespace FiscalOS.API.Login;
|
|
||||||
|
|
||||||
internal sealed class TokenService(
|
|
||||||
TimeProvider timeProvider,
|
|
||||||
IOptions<JwtOptions> jwtOptions
|
|
||||||
)
|
|
||||||
{
|
{
|
||||||
private const int RefreshTokenExpiryInHours = 12;
|
private const int RefreshTokenExpiryInHours = 12;
|
||||||
private readonly JwtOptions _jwtOptions = jwtOptions.Value;
|
private readonly IOptions<JwtOptions> _jwtOptions;
|
||||||
private readonly TimeProvider _timeProvider = timeProvider;
|
private readonly TimeProvider _timeProvider;
|
||||||
|
|
||||||
|
private TokenGenerator(
|
||||||
|
TimeProvider timeProvider,
|
||||||
|
IOptions<JwtOptions> jwtOptions
|
||||||
|
)
|
||||||
|
{
|
||||||
|
_timeProvider = timeProvider;
|
||||||
|
_jwtOptions = jwtOptions;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static TokenGenerator From(IServiceProvider serviceProvider)
|
||||||
|
{
|
||||||
|
var timeProvider = serviceProvider.GetRequiredService<TimeProvider>();
|
||||||
|
var jwtOptions = serviceProvider.GetRequiredService<IOptions<JwtOptions>>();
|
||||||
|
return new(timeProvider, jwtOptions);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static TokenGenerator From(
|
||||||
|
TimeProvider timeProvider,
|
||||||
|
IOptions<JwtOptions> jwtOptions
|
||||||
|
)
|
||||||
|
{
|
||||||
|
return new(timeProvider, jwtOptions);
|
||||||
|
}
|
||||||
|
|
||||||
public string GenerateAccessToken(User user)
|
public string GenerateAccessToken(User user)
|
||||||
{
|
{
|
||||||
var tokenHandler = new JwtSecurityTokenHandler();
|
var tokenHandler = new JwtSecurityTokenHandler();
|
||||||
var secretKeyBytes = Encoding.UTF8.GetBytes(_jwtOptions.Secret);
|
var secretKeyBytes = Encoding.UTF8.GetBytes(_jwtOptions.Value.Secret);
|
||||||
var issuedAt = _timeProvider.GetUtcNow();
|
var issuedAt = _timeProvider.GetUtcNow();
|
||||||
var expiresAt = issuedAt.AddMinutes(_jwtOptions.ExpiryInMinutes);
|
var expiresAt = issuedAt.AddMinutes(_jwtOptions.Value.ExpiryInMinutes);
|
||||||
List<Claim> claims = [
|
List<Claim> claims = [
|
||||||
new(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()),
|
new(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()),
|
||||||
new(JwtRegisteredClaimNames.Sub, user.Id.ToString()),
|
new(JwtRegisteredClaimNames.Sub, user.Id.ToString()),
|
||||||
@@ -35,8 +46,8 @@ internal sealed class TokenService(
|
|||||||
Subject = new(claims),
|
Subject = new(claims),
|
||||||
IssuedAt = issuedAt.UtcDateTime,
|
IssuedAt = issuedAt.UtcDateTime,
|
||||||
Expires = expiresAt.UtcDateTime,
|
Expires = expiresAt.UtcDateTime,
|
||||||
Issuer = _jwtOptions.Issuer,
|
Issuer = _jwtOptions.Value.Issuer,
|
||||||
Audience = _jwtOptions.Audience,
|
Audience = _jwtOptions.Value.Audience,
|
||||||
SigningCredentials = new(
|
SigningCredentials = new(
|
||||||
new SymmetricSecurityKey(secretKeyBytes),
|
new SymmetricSecurityKey(secretKeyBytes),
|
||||||
SecurityAlgorithms.HmacSha256Signature
|
SecurityAlgorithms.HmacSha256Signature
|
||||||
@@ -64,4 +75,4 @@ internal sealed class TokenService(
|
|||||||
var token = Convert.ToBase64String(randomBytes);
|
var token = Convert.ToBase64String(randomBytes);
|
||||||
return token;
|
return token;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" />
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" />
|
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Hosting" />
|
<PackageReference Include="Microsoft.Extensions.Hosting" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|||||||
@@ -1,8 +1,12 @@
|
|||||||
|
global using System.IdentityModel.Tokens.Jwt;
|
||||||
|
global using System.Security.Claims;
|
||||||
global using System.Security.Cryptography;
|
global using System.Security.Cryptography;
|
||||||
|
global using System.Text;
|
||||||
|
|
||||||
|
global using FiscalOS.Core.Authentication;
|
||||||
global using FiscalOS.Core.Identity;
|
global using FiscalOS.Core.Identity;
|
||||||
|
global using FiscalOS.Infra.Authentication;
|
||||||
global using FiscalOS.Infra.Data;
|
global using FiscalOS.Infra.Data;
|
||||||
global using FiscalOS.Infra.Identity;
|
|
||||||
|
|
||||||
global using Microsoft.EntityFrameworkCore;
|
global using Microsoft.EntityFrameworkCore;
|
||||||
global using Microsoft.EntityFrameworkCore.Diagnostics;
|
global using Microsoft.EntityFrameworkCore.Diagnostics;
|
||||||
@@ -10,4 +14,5 @@ global using Microsoft.Extensions.Configuration;
|
|||||||
global using Microsoft.Extensions.DependencyInjection;
|
global using Microsoft.Extensions.DependencyInjection;
|
||||||
global using Microsoft.Extensions.Hosting;
|
global using Microsoft.Extensions.Hosting;
|
||||||
global using Microsoft.Extensions.Logging;
|
global using Microsoft.Extensions.Logging;
|
||||||
global using Microsoft.Extensions.Options;
|
global using Microsoft.Extensions.Options;
|
||||||
|
global using Microsoft.IdentityModel.Tokens;
|
||||||
Reference in New Issue
Block a user