diff --git a/src/Infrastructure/Identity/IdentityService.cs b/src/Infrastructure/Identity/IdentityService.cs index 3d9bbc0..4842668 100644 --- a/src/Infrastructure/Identity/IdentityService.cs +++ b/src/Infrastructure/Identity/IdentityService.cs @@ -1,9 +1,5 @@ -using System; -using System.Collections.Generic; using Google.Apis.Oauth2.v2.Data; using System.Security.Claims; -using System.Threading; -using System.Threading.Tasks; using Hutopy.Application.Common.Interfaces; using Hutopy.Application.Common.Models; using Hutopy.Application.Users.Models; @@ -12,7 +8,7 @@ using Hutopy.Infrastructure.Utils; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Identity; -using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.Options; namespace Hutopy.Infrastructure.Identity; @@ -22,7 +18,7 @@ public class IdentityService( IUserClaimsPrincipalFactory userClaimsPrincipalFactory, IAuthorizationService authorizationService, IHttpContextAccessor contextAccessor, - IConfiguration configuration + IOptionsSnapshot jwtOptions ) : IIdentityService { @@ -424,13 +420,12 @@ public class IdentityService( var user = await GetUserByUserNameAsync(userName); if (user is null) throw new InvalidOperationException(); - - var jwtSection = configuration.GetRequiredSection("Authentication:Jwt"); var token = JwtTokenHelper.GenerateJwtToken( - issuer: jwtSection["Issuer"] ?? "", - audience: jwtSection["Audience"] ?? "", - key: jwtSection["Key"] ?? "", + expiresIn: jwtOptions.Value.Lifetime, + issuer: jwtOptions.Value.Issuer, + audience: jwtOptions.Value.Audience, + key: jwtOptions.Value.Key, userId: user.Id, email: user.Email, firstname: user.FirstName, diff --git a/src/Infrastructure/Identity/JwtOptions.cs b/src/Infrastructure/Identity/JwtOptions.cs new file mode 100644 index 0000000..0f4214c --- /dev/null +++ b/src/Infrastructure/Identity/JwtOptions.cs @@ -0,0 +1,11 @@ +namespace Hutopy.Infrastructure.Identity; + +public record JwtOptions +{ + public const string SectionName = "Authentication:Jwt"; + + public required TimeSpan Lifetime { get; init; } + public required string Issuer { get; init; } + public required string Audience { get; init; } + public required string Key { get; init; } +} diff --git a/src/Infrastructure/Utils/GenerateJwtToken.cs b/src/Infrastructure/Utils/GenerateJwtToken.cs index 1139f25..a5613d6 100644 --- a/src/Infrastructure/Utils/GenerateJwtToken.cs +++ b/src/Infrastructure/Utils/GenerateJwtToken.cs @@ -1,6 +1,4 @@ -using System; -using System.Collections.Generic; -using System.IdentityModel.Tokens.Jwt; +using System.IdentityModel.Tokens.Jwt; using System.Security.Claims; using System.Text; using Microsoft.IdentityModel.Tokens; @@ -10,6 +8,7 @@ namespace Hutopy.Infrastructure.Utils; public static class JwtTokenHelper { public static string GenerateJwtToken( + TimeSpan expiresIn, string issuer, string audience, string key, @@ -42,7 +41,7 @@ public static class JwtTokenHelper issuer: issuer, audience: audience, claims: claims, - expires: DateTime.Now.AddMinutes(1440), + expires: DateTime.Now.Add(expiresIn), signingCredentials: credentials); return new JwtSecurityTokenHandler().WriteToken(token); diff --git a/src/Web/Controllers/GoogleController.cs b/src/Web/Controllers/GoogleController.cs index 38e04e7..db86eb4 100644 --- a/src/Web/Controllers/GoogleController.cs +++ b/src/Web/Controllers/GoogleController.cs @@ -1,14 +1,20 @@ using System.Security.Claims; using Hutopy.Application.Common.Interfaces; +using Hutopy.Infrastructure.Identity; using Hutopy.Infrastructure.Utils; using Microsoft.AspNetCore.Authentication; using Microsoft.AspNetCore.Authentication.Cookies; using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.Options; using Newtonsoft.Json.Linq; namespace Hutopy.Web.Controllers; -public class GoogleController(IIdentityService identityService, IHttpClientFactory httpClientFactory, IConfiguration configuration) : Controller +public class GoogleController( + IIdentityService identityService, + IHttpClientFactory httpClientFactory, + IOptionsSnapshot jwtOptions) + : Controller { [HttpPost("/api/google/sign-in")] public async Task SignIn([FromBody] GoogleSignInRequest request) @@ -61,12 +67,11 @@ public class GoogleController(IIdentityService identityService, IHttpClientFacto CookieAuthenticationDefaults.AuthenticationScheme, new ClaimsPrincipal(claimsIdentity)); - var jwtSection = configuration.GetRequiredSection("Authentication:Jwt"); - var token = JwtTokenHelper.GenerateJwtToken( - jwtSection["Issuer"] ?? throw new ArgumentNullException("The Jwt issuer is missing."), - jwtSection["Audience"] ?? throw new ArgumentNullException("The Jwt audience is missing."), - jwtSection["Key"] ?? throw new ArgumentNullException("The Jwt key is missing."), + jwtOptions.Value.Lifetime, + jwtOptions.Value.Issuer, + jwtOptions.Value.Audience, + jwtOptions.Value.Key, user.Id, user.Email, user.FirstName, diff --git a/src/Web/Program.cs b/src/Web/Program.cs index 097dac9..c7967fa 100644 --- a/src/Web/Program.cs +++ b/src/Web/Program.cs @@ -3,6 +3,7 @@ using FastEndpoints; using Hutopy.Application; using Hutopy.Infrastructure; using Hutopy.Infrastructure.Data; +using Hutopy.Infrastructure.Identity; using Hutopy.Web; using Hutopy.Web.Contents.Data; using Hutopy.Web.Messages.Data; @@ -89,6 +90,8 @@ builder.Services.AddDbContext((_, options) => options.UseSqlServer(builder.Configuration.GetConnectionString("ContentStore")); }); +builder.Services.Configure(builder.Configuration.GetRequiredSection(JwtOptions.SectionName)); + var app = builder.Build(); app.UseForwardedHeaders( diff --git a/src/Web/appsettings.Development.json b/src/Web/appsettings.Development.json index decba8e..f394dcb 100644 --- a/src/Web/appsettings.Development.json +++ b/src/Web/appsettings.Development.json @@ -14,6 +14,7 @@ }, "Authentication": { "Jwt": { + "Lifetime": "1.00:00:00", "Audience": "hutopy", "Issuer": "https://auth.hutopy.com", "Key": "b2df428b9929d3ace7c598bbf4e496b2f0b71ab3cd4f94540356cfc35b000000" diff --git a/src/Web/appsettings.json b/src/Web/appsettings.json index 222224e..d7257bd 100644 --- a/src/Web/appsettings.json +++ b/src/Web/appsettings.json @@ -6,5 +6,10 @@ "Microsoft.Hosting.Lifetime": "Information" } }, - "AllowedHosts": "*" + "AllowedHosts": "*", + "Authentication": { + "Jwt": { + "Lifetime": "00:30:00" + } + } } \ No newline at end of file