HandlerInterceptor的preHandle不生效主因是未注册到Spring MVC拦截器链,需用@Component标记并实现WebMvcConfigurer重写addInterceptors方法显式注册。

HandlerInterceptor 的 preHandle 为什么总不生效
不是方法没写对,而是没注册进 Spring MVC 的拦截器链。Spring Boot 2.0+ 默认不自动扫描 HandlerInterceptor 实现类,必须显式配置。
- 确保拦截器类被
@Component标记,且在主启动类包扫描路径下 - 实现
WebMvcConfigurer接口,重写addInterceptors方法,调用registry.addInterceptor(...) - 注意路径匹配:用
/**拦所有接口,但静态资源(如/static/**)可能被默认忽略,需手动排除或调整顺序 - 如果用了 WebFlux,
HandlerInterceptor完全不适用——它只属于 Spring MVC(基于 Servlet),WebFlux 要用WebFilter
权限校验该放在 preHandle 还是 afterCompletion
只在 preHandle 做鉴权。它的返回值直接控制请求是否继续执行:返回 false 就中断链路,不会进入 Controller;而 afterCompletion 是事后回调,此时响应可能已写出,再拦已无意义。
-
preHandle中建议只做「读取 token → 解析用户身份 → 查权限 → 决定放行/拒访」这四步,别塞业务逻辑 - 拒绝时不要只写
response.setStatus(403),要主动response.getWriter().write(...)输出 JSON 错误体,否则前端收不到结构化错误 - 避免在
preHandle里查数据库判断权限——高并发下会成瓶颈,应预加载到内存(如ConcurrentHashMap缓存角色-权限映射)或走 Redis
如何从 HttpServletRequest 安全提取 token 并校验
Token 不该只从 Header 取,更不能拼接进 URL(易泄露)。主流做法是统一走 Authorization: Bearer <token>,但要注意大小写、空格、过期和签名验证。
- 用
request.getHeader("Authorization")获取后,先检查是否以"Bearer "开头(注意末尾空格),再截取 token 字符串 - JWT token 必须校验签名(用
io.jsonwebtoken的Jwts.parser().setSigningKey(...).parseClaimsJws(...)),否则攻击者可伪造 payload - 别忽略
ExpiredJwtException和SignatureException,它们要分别返回 401 和 403,语义不能混 - 解析出的
claims里应含userId和roles,而不是每次再查库捞用户信息
为什么放行登录接口却还是被拦截了
路径配置写错了。常见坑是用了 Ant 风格通配但没覆盖实际请求路径,比如登录接口是 POST /api/v1/auth/login,却只放行了 /login 或 /auth/login。
立即学习“Java免费学习笔记(深入)”;
- 在
addInterceptors里用.excludePathPatterns()显式排除,路径必须和实际请求 URI 完全一致(区分大小写、前导斜杠) - 排除列表要写全:登录、验证码、健康检查、Swagger 资源(
/v3/api-docs/**,/swagger-ui/**)等 - 如果用了网关(如 Spring Cloud Gateway),拦截器在网关层就该处理,后端服务再加一遍反而冗余,还可能导致 header 丢失
- 调试时可在
preHandle开头加日志:log.info("URI: {}, Method: {}", request.getRequestURI(), request.getMethod()),确认拦截器真收到了请求
权限拦截真正的复杂点不在代码怎么写,而在「谁有权限访问哪个 API」这个规则怎么定义、存储和更新。硬编码在 if 判断里?改一次发一版?权限数据存在 DB 里?那每次请求都要查表。最麻烦的是 RBAC 模型里「角色继承」「权限动态变更」「接口级 vs 数据级」这些维度叠加之后,拦截器里那一行 if (!hasPermission(...)) 底下藏着的其实是整个授权体系的设计选择。










