using System; using System.IdentityModel.Tokens.Jwt; using System.Linq; using System.Text; using System.Threading.Tasks; using Microsoft.AspNetCore.Http; using Microsoft.Extensions.Options; using Microsoft.IdentityModel.Tokens; using Haoliang.Core.Services; using Haoliang.Models.Common; namespace Haoliang.Api.Middleware { public class JwtMiddleware { private readonly RequestDelegate _next; private readonly IAuthService _authService; private readonly JwtSettings _jwtSettings; public JwtMiddleware(RequestDelegate next, IAuthService authService, IOptions jwtSettings) { _next = next; _authService = authService; _jwtSettings = jwtSettings.Value; } public async Task Invoke(HttpContext context) { var token = context.Request.Headers["Authorization"].FirstOrDefault()?.Split(" ").Last(); if (token != null) await AttachUserToContext(context, token); await _next(context); } private async Task AttachUserToContext(HttpContext context, string token) { try { var tokenHandler = new JwtSecurityTokenHandler(); var key = Encoding.ASCII.GetBytes(_jwtSettings.Secret); tokenHandler.ValidateToken(token, new TokenValidationParameters { ValidateIssuerSigningKey = true, IssuerSigningKey = new SymmetricSecurityKey(key), ValidateIssuer = false, ValidateAudience = false, ClockSkew = TimeSpan.Zero }, out SecurityToken validatedToken); var jwtToken = (JwtSecurityToken)validatedToken; var userId = int.Parse(jwtToken.Claims.First(x => x.Type == "id").Value); // Attach user to context on successful jwt validation context.Items["User"] = await _authService.GetUserByIdAsync(userId); } catch (Exception ex) { // Token is not valid // Log the error but don't throw, allow the request to continue // The authorization filter will handle the authentication failure } } } public class JwtSettings { public string Secret { get; set; } public string Issuer { get; set; } public string Audience { get; set; } public int ExpirationMinutes { get; set; } = 60; } public static class JwtMiddlewareExtensions { public static IApplicationBuilder UseJwtMiddleware(this IApplicationBuilder builder) { return builder.UseMiddleware(); } } }