first commit
This commit is contained in:
@@ -0,0 +1,114 @@
|
||||
using Fitness_core_BE.Models.IOs;
|
||||
using Microsoft.AspNetCore.Mvc.Filters;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.IdentityModel.Tokens;
|
||||
using System.IdentityModel.Tokens.Jwt;
|
||||
using System.Security.Claims;
|
||||
using System.Security.Cryptography;
|
||||
|
||||
namespace Fitness_core_BE.Helpers
|
||||
{
|
||||
public class JwtMiddleware
|
||||
{
|
||||
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
|
||||
public class CustomMiddlewareAttribute : Attribute, IAsyncActionFilter
|
||||
{
|
||||
public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
|
||||
{
|
||||
var config = context.HttpContext.RequestServices.GetService<IConfiguration>();
|
||||
|
||||
string token = null;
|
||||
|
||||
var authHeader = context.HttpContext.Request.Headers["MobileAuthToken"].FirstOrDefault();
|
||||
if (!string.IsNullOrWhiteSpace(authHeader) && authHeader.StartsWith("Bearer "))
|
||||
{
|
||||
token = authHeader.Substring("Bearer ".Length).Trim();
|
||||
}
|
||||
|
||||
if (string.IsNullOrWhiteSpace(token))
|
||||
{
|
||||
token = context.HttpContext.Request.Cookies["access_token"];
|
||||
}
|
||||
|
||||
if (string.IsNullOrWhiteSpace(token))
|
||||
{
|
||||
context.HttpContext.Response.StatusCode = 401;
|
||||
await context.HttpContext.Response.WriteAsJsonAsync(new ApiResponse<object>
|
||||
{
|
||||
StatusCode = 401,
|
||||
Message = "Authentication cookie is missing",
|
||||
Data = null
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
var tokenHandler = new JwtSecurityTokenHandler();
|
||||
|
||||
var xmlKey = config["Jwt:PublicKey"];
|
||||
|
||||
if (string.IsNullOrWhiteSpace(xmlKey))
|
||||
throw new SecurityTokenException("JWT public key not configured.");
|
||||
|
||||
// Use FromXmlString (same approach as the Auth service's RsaKeyProvider)
|
||||
// to ensure identical key loading behavior
|
||||
var rsa = RSA.Create();
|
||||
rsa.FromXmlString(xmlKey);
|
||||
var rsaParameters = rsa.ExportParameters(false);
|
||||
|
||||
// Create RsaSecurityKey from RSAParameters directly (not from RSA object)
|
||||
// to avoid object lifecycle/disposal issues with IdentityModel v8+
|
||||
var key = new RsaSecurityKey(rsaParameters)
|
||||
{
|
||||
KeyId = ComputeKeyId(rsaParameters)
|
||||
};
|
||||
|
||||
var parameters = new TokenValidationParameters
|
||||
{
|
||||
ValidateIssuerSigningKey = true,
|
||||
IssuerSigningKey = key,
|
||||
ValidateIssuer = true,
|
||||
ValidIssuer = config["Jwt:Issuer"],
|
||||
ValidateAudience = true,
|
||||
ValidAudience = config["Jwt:Audience"],
|
||||
ValidateLifetime = true,
|
||||
ClockSkew = TimeSpan.FromMinutes(2)
|
||||
};
|
||||
|
||||
var principal = tokenHandler.ValidateToken(token, parameters, out SecurityToken _);
|
||||
|
||||
context.HttpContext.User = principal;
|
||||
|
||||
context.HttpContext.Items["UserId"] = principal.FindFirst("UserId")?.Value;
|
||||
context.HttpContext.Items["Email"] = principal.FindFirst("Email")?.Value;
|
||||
context.HttpContext.Items["UserType"] = principal.FindFirst("UserType")?.Value;
|
||||
context.HttpContext.Items["RoleId"] = principal.FindFirst("RoleId")?.Value;
|
||||
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
context.HttpContext.Response.StatusCode = 401;
|
||||
await context.HttpContext.Response.WriteAsJsonAsync(new ApiResponse<object>
|
||||
{
|
||||
StatusCode = 401,
|
||||
Message = "Invalid or expired token in cookie",
|
||||
Data = null
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
await next();
|
||||
}
|
||||
|
||||
private static string ComputeKeyId(RSAParameters publicParameters)
|
||||
{
|
||||
var modulus = publicParameters.Modulus ?? Array.Empty<byte>();
|
||||
var exponent = publicParameters.Exponent ?? Array.Empty<byte>();
|
||||
var payload = $"{Convert.ToBase64String(modulus)}.{Convert.ToBase64String(exponent)}";
|
||||
var hash = SHA256.HashData(System.Text.Encoding.UTF8.GetBytes(payload));
|
||||
return Base64UrlEncoder.Encode(hash);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user