如何在ASP.NET Core Web API中仅读取JWT Token用户信息而不验证
Got it, let's break this down for you! Since you don't want to handle JWT validation locally and just need to pull the sub claim while offloading validation to a third-party API, here's a clean approach tailored to ASP.NET Core Web API:
We'll create a reusable action filter to handle three key tasks: extracting the JWT from the request, parsing the sub claim without local validation, and validating the token via your third-party API. This keeps your controller code clean and centralized.
Step 2: Implement the Custom Filter
Here's the full code for the filter, which uses IHttpClientFactory to call the third-party validation API and JwtSecurityTokenHandler to parse the token without verifying its signature:
using Microsoft.AspNetCore.Mvc.Filters; using System.IdentityModel.Tokens.Jwt; using System.Net.Http.Json; public class JwtSubExtractorFilter : IAsyncActionFilter { private readonly IHttpClientFactory _httpClientFactory; // Replace with your actual third-party validation API endpoint private const string ThirdPartyValidationEndpoint = "https://your-third-party-api.com/api/validate-token"; public JwtSubExtractorFilter(IHttpClientFactory httpClientFactory) { _httpClientFactory = httpClientFactory; } public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next) { // 1. Extract Bearer Token from Authorization header if (!context.HttpContext.Request.Headers.TryGetValue("Authorization", out var authHeader) || !authHeader.ToString().StartsWith("Bearer ", StringComparison.OrdinalIgnoreCase)) { context.Result = new Microsoft.AspNetCore.Mvc.UnauthorizedResult(); return; } var jwtToken = authHeader.ToString().Substring("Bearer ".Length).Trim(); try { // 2. Parse the token to get the 'sub' claim (NO local validation) var tokenHandler = new JwtSecurityTokenHandler(); var parsedToken = tokenHandler.ReadJwtToken(jwtToken); var userId = parsedToken.Claims.FirstOrDefault(c => c.Type == JwtRegisteredClaimNames.Sub)?.Value; if (string.IsNullOrEmpty(userId)) { context.Result = new Microsoft.AspNetCore.Mvc.BadRequestObjectResult("JWT token missing required 'sub' claim"); return; } // 3. Validate token via third-party API var httpClient = _httpClientFactory.CreateClient(); var validationResponse = await httpClient.PostAsJsonAsync(ThirdPartyValidationEndpoint, new { Token = jwtToken }); if (!validationResponse.IsSuccessStatusCode) { context.Result = new Microsoft.AspNetCore.Mvc.UnauthorizedResult(); return; } // 4. Attach the user ID to the request context for later use context.HttpContext.Items["UserId"] = userId; // Proceed to the target action await next(); } catch (ArgumentException) { // Catch invalid JWT format errors context.Result = new Microsoft.AspNetCore.Mvc.BadRequestObjectResult("Invalid JWT token format"); return; } catch (HttpRequestException) { // Handle third-party API connectivity issues context.Result = new Microsoft.AspNetCore.Mvc.StatusCodeResult(StatusCodes.Status503ServiceUnavailable); return; } } }
Step 3: Register Dependencies in Program.cs
You need to register the filter and IHttpClientFactory (for calling the third-party API) in your startup code:
var builder = WebApplication.CreateBuilder(args); // Add controllers builder.Services.AddControllers(); // Register HttpClientFactory for API calls builder.Services.AddHttpClient(); // Register the custom filter as a scoped service builder.Services.AddScoped<JwtSubExtractorFilter>(); var app = builder.Build(); app.UseHttpsRedirection(); app.UseAuthorization(); // Apply the filter globally to all endpoints (or use per-controller/action attributes) app.MapControllers().AddEndpointFilter<JwtSubExtractorFilter>(); app.Run();
Step 4: Access the sub Claim in Your Controllers
Once the filter runs successfully, you can pull the user ID from HttpContext.Items in any controller action:
[ApiController] [Route("api/[controller]")] public class UserController : ControllerBase { [HttpGet("profile")] public IActionResult GetUserProfile() { if (HttpContext.Items.TryGetValue("UserId", out var userId)) { // Use the userId in your business logic return Ok(new { UserId = userId.ToString(), Message = "Profile data here" }); } return Unauthorized(); } }
- Per-Action/Controller Application: If you don't want the filter to apply globally, replace the global registration with the
[ServiceFilter(typeof(JwtSubExtractorFilter))]attribute on specific controllers or actions. - Error Handling: The example includes basic error handling for missing tokens, invalid formats, and third-party API failures—adjust this to match your application's error response requirements.
- No Local Validation: The
ReadJwtTokenmethod only parses the token's content; it does NOT verify the signature, expiration, or issuer. Never skip the third-party validation step—this is critical for security. - Token Sources: If your JWTs come from somewhere other than the Authorization header (e.g., query params, cookies), modify the token extraction logic in the filter.
内容的提问来源于stack exchange,提问作者zash707

