Adds Options for JwtAuthentication (30min prod - 1day dev)

This commit is contained in:
Jonathan Bourdon
2024-07-06 22:13:56 -04:00
parent eca4f60412
commit 256fa3df91
7 changed files with 41 additions and 22 deletions

View File

@@ -1,9 +1,5 @@
using System;
using System.Collections.Generic;
using Google.Apis.Oauth2.v2.Data; using Google.Apis.Oauth2.v2.Data;
using System.Security.Claims; using System.Security.Claims;
using System.Threading;
using System.Threading.Tasks;
using Hutopy.Application.Common.Interfaces; using Hutopy.Application.Common.Interfaces;
using Hutopy.Application.Common.Models; using Hutopy.Application.Common.Models;
using Hutopy.Application.Users.Models; using Hutopy.Application.Users.Models;
@@ -12,7 +8,7 @@ using Hutopy.Infrastructure.Utils;
using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Identity; using Microsoft.AspNetCore.Identity;
using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Options;
namespace Hutopy.Infrastructure.Identity; namespace Hutopy.Infrastructure.Identity;
@@ -22,7 +18,7 @@ public class IdentityService(
IUserClaimsPrincipalFactory<ApplicationUser> userClaimsPrincipalFactory, IUserClaimsPrincipalFactory<ApplicationUser> userClaimsPrincipalFactory,
IAuthorizationService authorizationService, IAuthorizationService authorizationService,
IHttpContextAccessor contextAccessor, IHttpContextAccessor contextAccessor,
IConfiguration configuration IOptionsSnapshot<JwtOptions> jwtOptions
) )
: IIdentityService : IIdentityService
{ {
@@ -424,13 +420,12 @@ public class IdentityService(
var user = await GetUserByUserNameAsync(userName); var user = await GetUserByUserNameAsync(userName);
if (user is null) throw new InvalidOperationException(); if (user is null) throw new InvalidOperationException();
var jwtSection = configuration.GetRequiredSection("Authentication:Jwt");
var token = JwtTokenHelper.GenerateJwtToken( var token = JwtTokenHelper.GenerateJwtToken(
issuer: jwtSection["Issuer"] ?? "", expiresIn: jwtOptions.Value.Lifetime,
audience: jwtSection["Audience"] ?? "", issuer: jwtOptions.Value.Issuer,
key: jwtSection["Key"] ?? "", audience: jwtOptions.Value.Audience,
key: jwtOptions.Value.Key,
userId: user.Id, userId: user.Id,
email: user.Email, email: user.Email,
firstname: user.FirstName, firstname: user.FirstName,

View File

@@ -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; }
}

View File

@@ -1,6 +1,4 @@
using System; using System.IdentityModel.Tokens.Jwt;
using System.Collections.Generic;
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims; using System.Security.Claims;
using System.Text; using System.Text;
using Microsoft.IdentityModel.Tokens; using Microsoft.IdentityModel.Tokens;
@@ -10,6 +8,7 @@ namespace Hutopy.Infrastructure.Utils;
public static class JwtTokenHelper public static class JwtTokenHelper
{ {
public static string GenerateJwtToken( public static string GenerateJwtToken(
TimeSpan expiresIn,
string issuer, string issuer,
string audience, string audience,
string key, string key,
@@ -42,7 +41,7 @@ public static class JwtTokenHelper
issuer: issuer, issuer: issuer,
audience: audience, audience: audience,
claims: claims, claims: claims,
expires: DateTime.Now.AddMinutes(1440), expires: DateTime.Now.Add(expiresIn),
signingCredentials: credentials); signingCredentials: credentials);
return new JwtSecurityTokenHandler().WriteToken(token); return new JwtSecurityTokenHandler().WriteToken(token);

View File

@@ -1,14 +1,20 @@
using System.Security.Claims; using System.Security.Claims;
using Hutopy.Application.Common.Interfaces; using Hutopy.Application.Common.Interfaces;
using Hutopy.Infrastructure.Identity;
using Hutopy.Infrastructure.Utils; using Hutopy.Infrastructure.Utils;
using Microsoft.AspNetCore.Authentication; using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authentication.Cookies; using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Options;
using Newtonsoft.Json.Linq; using Newtonsoft.Json.Linq;
namespace Hutopy.Web.Controllers; namespace Hutopy.Web.Controllers;
public class GoogleController(IIdentityService identityService, IHttpClientFactory httpClientFactory, IConfiguration configuration) : Controller public class GoogleController(
IIdentityService identityService,
IHttpClientFactory httpClientFactory,
IOptionsSnapshot<JwtOptions> jwtOptions)
: Controller
{ {
[HttpPost("/api/google/sign-in")] [HttpPost("/api/google/sign-in")]
public async Task<IActionResult> SignIn([FromBody] GoogleSignInRequest request) public async Task<IActionResult> SignIn([FromBody] GoogleSignInRequest request)
@@ -61,12 +67,11 @@ public class GoogleController(IIdentityService identityService, IHttpClientFacto
CookieAuthenticationDefaults.AuthenticationScheme, CookieAuthenticationDefaults.AuthenticationScheme,
new ClaimsPrincipal(claimsIdentity)); new ClaimsPrincipal(claimsIdentity));
var jwtSection = configuration.GetRequiredSection("Authentication:Jwt");
var token = JwtTokenHelper.GenerateJwtToken( var token = JwtTokenHelper.GenerateJwtToken(
jwtSection["Issuer"] ?? throw new ArgumentNullException("The Jwt issuer is missing."), jwtOptions.Value.Lifetime,
jwtSection["Audience"] ?? throw new ArgumentNullException("The Jwt audience is missing."), jwtOptions.Value.Issuer,
jwtSection["Key"] ?? throw new ArgumentNullException("The Jwt key is missing."), jwtOptions.Value.Audience,
jwtOptions.Value.Key,
user.Id, user.Id,
user.Email, user.Email,
user.FirstName, user.FirstName,

View File

@@ -3,6 +3,7 @@ using FastEndpoints;
using Hutopy.Application; using Hutopy.Application;
using Hutopy.Infrastructure; using Hutopy.Infrastructure;
using Hutopy.Infrastructure.Data; using Hutopy.Infrastructure.Data;
using Hutopy.Infrastructure.Identity;
using Hutopy.Web; using Hutopy.Web;
using Hutopy.Web.Contents.Data; using Hutopy.Web.Contents.Data;
using Hutopy.Web.Messages.Data; using Hutopy.Web.Messages.Data;
@@ -89,6 +90,8 @@ builder.Services.AddDbContext<ContentDbContext>((_, options) =>
options.UseSqlServer(builder.Configuration.GetConnectionString("ContentStore")); options.UseSqlServer(builder.Configuration.GetConnectionString("ContentStore"));
}); });
builder.Services.Configure<JwtOptions>(builder.Configuration.GetRequiredSection(JwtOptions.SectionName));
var app = builder.Build(); var app = builder.Build();
app.UseForwardedHeaders( app.UseForwardedHeaders(

View File

@@ -14,6 +14,7 @@
}, },
"Authentication": { "Authentication": {
"Jwt": { "Jwt": {
"Lifetime": "1.00:00:00",
"Audience": "hutopy", "Audience": "hutopy",
"Issuer": "https://auth.hutopy.com", "Issuer": "https://auth.hutopy.com",
"Key": "b2df428b9929d3ace7c598bbf4e496b2f0b71ab3cd4f94540356cfc35b000000" "Key": "b2df428b9929d3ace7c598bbf4e496b2f0b71ab3cd4f94540356cfc35b000000"

View File

@@ -6,5 +6,10 @@
"Microsoft.Hosting.Lifetime": "Information" "Microsoft.Hosting.Lifetime": "Information"
} }
}, },
"AllowedHosts": "*" "AllowedHosts": "*",
"Authentication": {
"Jwt": {
"Lifetime": "00:30:00"
}
}
} }