如何在ASP.NET中为除登录注册外的接口前置JWT验证?
Got it, let's solve this problem step by step. You absolutely can implement JWT validation using an Action Filter—you just need to access the request headers correctly from the filter context. Here's how to adapt your existing validation logic into a reusable filter, and apply it across your controllers while excluding the LogIn/Register endpoints.
1. Create a Custom JWT Authorization Action Filter
First, we'll build a custom ActionFilterAttribute that handles token extraction, validation, and returns an unauthorized response if validation fails. We'll integrate your existing validation logic here, and add checks to skip validation for endpoints that shouldn't require it (like LogIn/Register).
using Microsoft.AspNetCore.Mvc.Filters; using Microsoft.IdentityModel.Tokens; using System.IdentityModel.Tokens.Jwt; using System.Security.Claims; using System.Text; public class JwtAuthorizeAttribute : ActionFilterAttribute { public override void OnActionExecuting(ActionExecutingContext context) { // Skip validation if the action has [AllowAnonymous] attribute if (context.ActionDescriptor.EndpointMetadata.Any(em => em is AllowAnonymousAttribute)) { base.OnActionExecuting(context); return; } // Extract token from Authorization header if (!context.HttpContext.Request.Headers.TryGetValue("Authorization", out var tokenHeader)) { context.Result = new Microsoft.AspNetCore.Mvc.UnauthorizedResult(); return; } string token = tokenHeader.ToString(); if (!token.StartsWith("Bearer ", StringComparison.OrdinalIgnoreCase)) { context.Result = new Microsoft.AspNetCore.Mvc.UnauthorizedResult(); return; } string sToken = token.Substring(7); bool isValid = ValidateToken(sToken); if (!isValid) { context.Result = new Microsoft.AspNetCore.Mvc.UnauthorizedResult(); return; } // If validation passes, proceed with the action base.OnActionExecuting(context); } private bool ValidateToken(string token) { try { JwtSecurityTokenHandler tokenHandler = new JwtSecurityTokenHandler(); if (!tokenHandler.CanReadToken(token)) { return false; } JwtSecurityToken jwtToken = tokenHandler.ReadToken(token) as JwtSecurityToken; if (jwtToken == null) { return false; } TokenValidationParameters parameters = new TokenValidationParameters() { ValidateIssuer = true, ValidateAudience = true, ValidateLifetime = true, RequireExpirationTime = true, ValidAudience = "http://localhost", ValidIssuer = "http://localhost", IssuerSigningKey = new SymmetricSecurityKey(Encoding.Default.GetBytes(StandardValues.SecretKey)) }; SecurityToken securityToken; ClaimsPrincipal principal = tokenHandler.ValidateToken(token, parameters, out securityToken); return principal != null; } catch (Exception) { return false; } } }
2. Apply the Filter to Your Controllers
You have a few flexible options to apply this filter based on your needs:
Option 1: Global Application (Applies to All Endpoints by Default)
If you want validation to apply to every endpoint automatically (and only exclude LogIn/Register), register the filter globally in your Program.cs:
var builder = WebApplication.CreateBuilder(args); // Add services to the container. builder.Services.AddControllers(options => { options.Filters.Add<JwtAuthorizeAttribute>(); }); // ... rest of your service configuration var app = builder.Build(); // ... middleware configuration app.MapControllers(); app.Run();
Then, add the [AllowAnonymous] attribute to your LogIn and Register actions to bypass validation:
[ApiController] [Route("api/auth")] public class AuthController : ControllerBase { [HttpPost("login")] [AllowAnonymous] public IActionResult LogIn([FromBody] LoginModel model) { // Your login logic here return Ok(); } [HttpPost("register")] [AllowAnonymous] public IActionResult Register([FromBody] RegisterModel model) { // Your registration logic here return Ok(); } }
Option 2: Controller-Level Application
If you only want to enforce validation on specific controllers, add the [JwtAuthorize] attribute directly to those controllers:
[ApiController] [Route("api/users")] [JwtAuthorize] public class UsersController : ControllerBase { // All actions in this controller will require JWT validation [HttpGet] public IActionResult GetUsers() { return Ok(); } }
You can still use [AllowAnonymous] on individual actions within these controllers if you need to exempt specific endpoints.
3. Key Notes
- Token Format: Ensure your clients send the token in the
Authorizationheader using theBearerscheme (Bearer <your-token>)—the filter expects this format to extract the token correctly. - Immediate Failure Handling: If validation fails at any step, the filter returns a
401 Unauthorizedresponse right away, stopping the target action from executing. - Reusability: This filter encapsulates all your JWT validation logic, so you don't have to duplicate code across multiple controllers or actions.
内容的提问来源于stack exchange,提问作者AndreiB

