当前位置: 首页 > news >正文

别再乱写Filter和Interceptor了!SpringBoot登录校验实战,从令牌生成到统一拦截的完整流程

别再乱写Filter和Interceptor了!SpringBoot登录校验实战精要

登录校验是每个JavaWeb开发者必须掌握的核心技能,但很多人在实际项目中常常陷入技术选型的困惑——Filter和Interceptor究竟该如何选择?如何避免常见的配置陷阱?本文将带你从零构建一套完整的JWT登录校验体系,涵盖令牌生成、统一拦截、异常处理全流程,并深度解析Filter与Interceptor的适用场景与最佳实践。

1. 技术选型:Filter vs Interceptor的本质差异

1.1 架构层级与执行顺序

Filter和Interceptor最根本的区别在于它们的架构层级

// Filter属于Servlet规范 public class AuthFilter implements Filter { @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { // 预处理逻辑 chain.doFilter(request, response); // 放行 // 后处理逻辑 } } // Interceptor属于Spring MVC框架 public class AuthInterceptor implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) { // 控制器方法执行前处理 return true; // 是否继续执行 } }

它们的执行顺序遵循以下管道(以典型请求为例):

  1. Filter层CharacterEncodingFilterCorsFilter自定义AuthFilter
  2. DispatcherServlet:路由匹配
  3. Interceptor层LogInterceptorAuthInterceptor
  4. Controller方法:业务逻辑处理

关键提示:Filter对所有请求生效(包括静态资源),而Interceptor只拦截Controller方法调用

1.2 核心能力对比

通过下表可以清晰看出两者的适用场景:

特性FilterInterceptor
依赖框架Servlet规范(JavaWeb标准)Spring MVC框架
作用范围所有HTTP请求仅Controller方法调用
获取上下文Servlet API原生对象HandlerMethod参数解析
异常处理需自行实现可结合@ExceptionHandler
性能开销较低略高(需经过Spring上下文)
典型应用场景跨域处理、字符编码、全局认证权限校验、日志记录、参数预处理

1.3 经典误用场景分析

案例1:路径匹配陷阱

// 错误配置:Interceptor使用Servlet路径模式 registry.addInterceptor(authInterceptor) .addPathPatterns("/api/*"); // 无法匹配/api/users/1 // 正确做法:使用Ant风格路径 registry.addInterceptor(authInterceptor) .addPathPatterns("/api/**");

案例2:注解扫描遗漏

// 忘记添加扫描注解导致Filter失效 @SpringBootApplication @ServletComponentScan // 必须添加! public class Application { public static void main(String[] args) { SpringApplication.run(Application.class, args); } }

2. JWT令牌生成与校验实战

2.1 令牌生成最佳实践

采用JJWT库实现安全的令牌签发:

public class JwtUtils { private static final String SECRET_KEY = "your-256-bit-secret"; private static final long EXPIRATION = 86400000; // 24小时 public static String generateToken(UserDetails user) { return Jwts.builder() .setSubject(user.getUsername()) .claim("roles", user.getAuthorities()) .setIssuedAt(new Date()) .setExpiration(new Date(System.currentTimeMillis() + EXPIRATION)) .signWith(SignatureAlgorithm.HS256, SECRET_KEY) .compact(); } }

安全要点:

  • 使用HS256算法配合足够长度的密钥
  • 设置合理的过期时间(建议≤24小时)
  • 不要在令牌中存储敏感信息(如密码)

2.2 统一校验架构设计

推荐采用Filter+Interceptor双校验的混合模式:

  1. Filter层:基础校验(令牌存在性、格式验证)
  2. Interceptor层:细粒度权限控制(角色校验、权限匹配)
// Filter基础校验示例 public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException { HttpServletRequest request = (HttpServletRequest) req; String token = request.getHeader("Authorization"); if (token == null || !token.startsWith("Bearer ")) { sendError(response, 401, "Missing token"); return; } try { Claims claims = JwtUtils.parseToken(token.substring(7)); request.setAttribute("userClaims", claims); chain.doFilter(request, response); } catch (JwtException e) { sendError(response, 403, "Invalid token"); } }

3. 异常处理与响应封装

3.1 全局异常处理机制

建立统一的错误响应体系:

@RestControllerAdvice public class GlobalExceptionHandler { @ExceptionHandler(AuthenticationException.class) public ResponseEntity<ErrorResponse> handleAuthError(AuthenticationException ex) { return ResponseEntity.status(401) .body(new ErrorResponse(401, "AUTH_ERROR", ex.getMessage())); } @ExceptionHandler(MethodArgumentNotValidException.class) public ResponseEntity<ErrorResponse> handleValidationError( MethodArgumentNotValidException ex) { String message = ex.getBindingResult().getAllErrors() .stream().map(DefaultMessageSourceResolvable::getDefaultMessage) .collect(Collectors.joining("; ")); return ResponseEntity.status(400) .body(new ErrorResponse(400, "VALIDATION_ERROR", message)); } }

3.2 响应体标准化

定义通用响应结构:

public class ApiResponse<T> { private int code; private String message; private T data; private long timestamp = System.currentTimeMillis(); // 成功响应快捷方法 public static <T> ApiResponse<T> success(T data) { ApiResponse<T> response = new ApiResponse<>(); response.code = 200; response.message = "success"; response.data = data; return response; } }

4. 性能优化与安全加固

4.1 缓存令牌校验结果

避免重复解析JWT带来的性能开销:

@Cacheable(value = "tokenCache", key = "#token") public Claims validateAndCacheToken(String token) { return Jwts.parser() .setSigningKey(SECRET_KEY) .parseClaimsJws(token) .getBody(); }

4.2 安全防护措施

  • CSRF防护:对关键操作添加随机Token校验
  • 防重放攻击:在JWT中加入jti(JWT ID)和nonce
  • 速率限制:对登录接口实施限流(如Guava RateLimiter)
// 限流器配置示例 @Bean public RateLimiter loginRateLimiter() { return RateLimiter.create(5); // 每秒5个请求 } @PostMapping("/login") public ApiResponse<String> login(@RequestBody LoginRequest request) { if (!loginRateLimiter.tryAcquire()) { throw new RateLimitException("Too many requests"); } // ...正常登录逻辑 }

5. 现代替代方案:Spring Security整合

对于复杂系统,建议采用Spring Security + JWT组合方案:

@EnableWebSecurity public class SecurityConfig extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { http.csrf().disable() .authorizeRequests() .antMatchers("/auth/**").permitAll() .anyRequest().authenticated() .and() .addFilter(new JwtAuthenticationFilter(authenticationManager())) .addFilter(new JwtAuthorizationFilter(authenticationManager())) .sessionManagement() .sessionCreationPolicy(SessionCreationPolicy.STATELESS); } }

迁移路径建议:

  1. 从简单Filter/Interceptor开始原型开发
  2. 随着业务复杂度的提升逐步引入Spring Security
  3. 关键路径保持双重校验机制

登录校验系统的设计需要根据实际业务场景灵活调整。在最近的一个教育管理系统项目中,我们采用Filter处理基础认证+Interceptor实现权限控制的混合模式,配合Redis缓存令牌信息,使系统在日均10万次请求下保持<50ms的认证延迟。记住:没有放之四海而皆准的方案,只有最适合当前业务阶段的技术选型。

http://www.jsqmd.com/news/854396/

相关文章:

  • 终极指南:如何用VisualCppRedist AIO一次性彻底修复Windows运行库问题
  • 架构可视化革命:用draw.io重构深度学习设计范式
  • 团队冲刺个人博客——5.20
  • ISCE2安装实录:从踩遍GitHub issue里的坑,到总结出这份WSL2+Miniconda的保姆级避坑指南
  • 学习进度5/18
  • 光伏PLC与储能BMS数据通信物联网解决方案
  • 小白程序员必看:四步轻松构建你的第一个AI编码Agent,收藏学习!
  • 学习进度5/15
  • 学习进度5/19
  • 一文带你搞懂C# 异步编程(async/await)底层原理
  • 联发科MT6873核心板:5G安卓设备开发实战与硬件设计指南
  • 基于Spring Boot与Vue的Redis网页管理工具设计与实现
  • i.MX8MP开发实战:从启动到外设的典型问题排查与解决
  • 德国风湿免疫研究中心Andreas Radbruch发现人体骨髓存在具有多功能性水痘-带状疱疹病毒反应性记忆CD4⁺ T细胞
  • 基于RK3568的嵌入式AI主机开发实战:从模型部署到工业应用
  • Kafka 与 RocketMQ 在事务消息实现机制上有什么区别?
  • Collection | Gut–X axis
  • 流量卡分销代理平台用哪个靠谱佣金高?靠谱秒返和次月返大平台推荐 - 流量卡代理招商
  • 告别OTA升级烦恼:一份给高通平台开发者的A/B分区配置与避坑指南(Android 12/13实测)
  • JavaQuestPlayer终极指南:一站式QSP游戏开发与运行平台完全教程
  • Perplexity谣言查询实战手册:从输入到验证的7步黄金流程,附可复用提示词模板
  • 保姆级教程:在Ubuntu 22.04上用nvme-cli无损切换PM983A硬盘的4KN/512E模式
  • 2026 全国 AI 自习室品牌 / 公司权威推荐:八家主流品牌深度解析与全场景选型指南
  • 3步搞定MASA模组全家桶汉化:小白也能懂的完整教程
  • i.MX8MP嵌入式开发实战:四层问题定位法与五大疑难案例解析
  • 2026年AI论文写作软件实测排行,哪款真正适合毕业定稿?
  • Perplexity市场份额逆势增长22.6%的背后:3个未被报道的垂直场景落地案例(含医疗/法律领域真实POC数据)
  • 2026深度分析罗兰艺境B2B企业服务-物业服务GEO技术案例,测评深圳卓越物业优化过程与效果验证 - 罗兰艺境GEO
  • 抖音视频批量下载终极指南:3分钟实现无水印高效下载
  • ArcGIS实战:用20年土地利用数据,手把手教你计算动态度与程度指数(附贵州省数据)