基于.NET Core的JWT认证API与MVC客户端令牌校验优化咨询
嘿,这个重复校验的问题确实挺磨人的,我给你几个ASP.NET Core MVC里常用的优化方案,帮你把这些冗余代码彻底干掉:
方案一:自定义Action过滤器(最直接的封装方式)
把令牌校验逻辑封装成一个Action过滤器,然后全局注册或者给需要的控制器/方法添加特性,就能自动触发校验了。
步骤1:编写过滤器类
public class CheckJwtTokenFilter : ActionFilterAttribute { public override void OnActionExecuting(ActionExecutingContext context) { // 排除登录控制器,避免循环跳转 if (context.Controller is LoginController) { base.OnActionExecuting(context); return; } var jwtToken = context.HttpContext.Session.GetString("JwtToken"); var returnUrl = context.HttpContext.Request.Path + context.HttpContext.Request.QueryString; if (string.IsNullOrEmpty(jwtToken)) { // 令牌为空,跳转到登录页并携带原页面地址 context.Result = new RedirectToActionResult("Login", "Account", new { returnUrl }); return; } // 可选:额外校验令牌是否过期/有效 try { var tokenHandler = new JwtSecurityTokenHandler(); var jwtSecurityToken = tokenHandler.ReadJwtToken(jwtToken); if (jwtSecurityToken.ValidTo < DateTime.UtcNow) { context.Result = new RedirectToActionResult("Login", "Account", new { returnUrl }); } } catch { // 令牌解析失败,直接跳登录 context.Result = new RedirectToActionResult("Login", "Account", new { returnUrl }); } base.OnActionExecuting(context); } }
步骤2:注册过滤器
- 全局生效:所有控制器自动应用校验,在
Program.cs里添加:
builder.Services.AddControllersWithViews(options => { options.Filters.Add<CheckJwtTokenFilter>(); });
- 局部生效:只给特定控制器/方法加特性:
[CheckJwtToken] public class DashboardController : Controller { // 控制器逻辑... }
方案二:自定义授权策略(贴合ASP.NET Core授权体系)
如果想更贴合框架的授权机制,可以把令牌校验做成一个自定义授权策略,扩展性更强。
步骤1:定义授权要求和处理器
// 空的授权要求,仅作为标记 public class JwtTokenRequirement : IAuthorizationRequirement { } // 授权处理器,实现校验逻辑 public class JwtTokenHandler : AuthorizationHandler<JwtTokenRequirement> { protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, JwtTokenRequirement requirement) { var httpContext = context.Resource as HttpContext; if (httpContext == null) { context.Fail(); return Task.CompletedTask; } // 排除登录路径 if (httpContext.Request.Path.StartsWithSegments("/Account/Login")) { context.Succeed(requirement); return Task.CompletedTask; } var jwtToken = httpContext.Session.GetString("JwtToken"); var returnUrl = Uri.EscapeDataString(httpContext.Request.Path + httpContext.Request.QueryString); if (!string.IsNullOrEmpty(jwtToken)) { try { var tokenHandler = new JwtSecurityTokenHandler(); var jwtSecurityToken = tokenHandler.ReadJwtToken(jwtToken); if (jwtSecurityToken.ValidTo >= DateTime.UtcNow) { context.Succeed(requirement); return Task.CompletedTask; } } catch { } } // 令牌无效/不存在,跳转登录页 httpContext.Response.Redirect($"/Account/Login?returnUrl={returnUrl}"); context.Succeed(requirement); // 手动标记成功,避免后续授权拦截 return Task.CompletedTask; } }
步骤2:注册授权策略
在Program.cs里添加:
builder.Services.AddAuthorization(options => { options.AddPolicy("RequireValidJwtToken", policy => { policy.Requirements.Add(new JwtTokenRequirement()); }); }); // 注册授权处理器 builder.Services.AddScoped<IAuthorizationHandler, JwtTokenHandler>();
步骤3:在控制器上使用
[Authorize(Policy = "RequireValidJwtToken")] public class OrdersController : Controller { // 控制器逻辑... }
方案三:基类控制器(简单直接的继承方式)
如果不想用过滤器或授权策略,也可以创建一个基类控制器,把校验逻辑写在基类的OnActionExecuting方法里,所有需要校验的控制器都继承这个基类。
public class BaseAuthenticatedController : Controller { public override void OnActionExecuting(ActionExecutingContext context) { if (!(this is LoginController)) { var jwtToken = HttpContext.Session.GetString("JwtToken"); var returnUrl = Request.Path + Request.QueryString; if (string.IsNullOrEmpty(jwtToken)) { context.Result = RedirectToAction("Login", "Account", new { returnUrl }); return; } // 可选:校验令牌有效性 try { var tokenHandler = new JwtSecurityTokenHandler(); var jwtSecurityToken = tokenHandler.ReadJwtToken(jwtToken); if (jwtSecurityToken.ValidTo < DateTime.UtcNow) { context.Result = RedirectToAction("Login", "Account", new { returnUrl }); return; } } catch { context.Result = RedirectToAction("Login", "Account", new { returnUrl }); return; } } base.OnActionExecuting(context); } }
然后其他控制器继承基类:
public class ProfileController : BaseAuthenticatedController { // 控制器逻辑... }
额外小建议
关于令牌存储:你用Session是可行的,但生产环境建议配置分布式缓存(比如Redis)来存储Session,避免单机部署时的Session丢失问题。另外也可以考虑把JWT存在HttpOnly的Cookie里,安全性更高,也更容易和ASP.NET Core的认证系统集成。
内容的提问来源于stack exchange,提问作者ironcurtain
相关产品推荐
相关产品推荐

