💡 开篇故事:一次“未授权访问”引发的数据泄露
某后台管理系统因未对管理接口做权限校验,导致外部用户通过URL猜测访问到敏感数据。问题根源:权限校验逻辑分散在各个Controller中,漏掉了部分接口!直到引入全局权限拦截器,统一拦截所有请求进行身份验证,才彻底堵住漏洞。
🔍 第一章:Interceptor是谁?为何重要?
Interceptor(拦截器) 是Spring MVC框架的核心组件,用于在Controller处理请求前后及视图渲染后插入自定义逻辑,实现:
- 公共逻辑复用:如鉴权、日志、性能监控。
- 请求流程管控:中断非法请求(如未登录用户访问)。
- 数据预处理:参数校验、国际化设置。
核心定位:Spring MVC层的“把关者”,专注Web请求处理链路的统一控制。
🛠️ 第二章:Interceptor生命周期与核心方法
1️⃣ 生命周期
- preHandle:Controller方法执行前调用(可中断请求)。
- postHandle:Controller方法执行后,视图渲染前调用(可修改ModelAndView)。
- afterCompletion:视图渲染后调用(资源清理、性能统计)。
2️⃣ 核心方法详解
public class AuthInterceptor implements HandlerInterceptor {
// 1. 预处理:返回true放行,false中断
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
String token = request.getHeader("Authorization");
return isValidToken(token); // 鉴权逻辑
}
// 2. 后处理:可修改ModelAndView
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
ModelAndView modelAndView) {
modelAndView.addObject("timestamp", System.currentTimeMillis());
}
// 3. 最终处理:异常信息统计
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler,
Exception ex) {
logRequestCost(request); // 记录请求耗时
}
}
🔧 第三章:Interceptor实战——四大应用场景
1️⃣ 接口权限校验
public class AuthInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
if (handler instanceof HandlerMethod) {
HandlerMethod method = (HandlerMethod) handler;
// 检查方法上的注解
if (method.hasMethodAnnotation(RequireLogin.class)) {
return checkLogin(request);
}
}
return true;
}
}
2️⃣ 请求日志记录
public class LogInterceptor implements HandlerInterceptor {
private ThreadLocal<Long> startTime = new ThreadLocal<>();
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
startTime.set(System.currentTimeMillis());
log.info("Request URL: {}", request.getRequestURL());
return true;
}
@Override
public void afterCompletion(...) {
long cost = System.currentTimeMillis() - startTime.get();
log.info("Request cost: {}ms", cost);
startTime.remove();
}
}
3️⃣ 全局异常预处理
public class ExceptionInterceptor implements HandlerInterceptor {
@Override
public void postHandle(...) {
if (ex != null) {
response.setStatus(500);
response.getWriter().write("{\"code\":500, \"msg\":\"服务异常\"}");
}
}
}
4️⃣ 多租户数据隔离
public class TenantInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
String tenantId = request.getHeader("X-Tenant-Id");
TenantContext.setCurrentTenant(tenantId);
return true;
}
@Override
public void afterCompletion(...) {
TenantContext.clear();
}
}
📊 第四章:Interceptor配置与执行顺序控制
1️⃣ 注册Interceptor(Java Config)
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new AuthInterceptor())
.addPathPatterns("/api/**")
.excludePathPatterns("/api/public/**");
registry.addInterceptor(new LogInterceptor())
.order(1) // 执行顺序:数字越小优先级越高
.addPathPatterns("/**");
}
}
2️⃣ 执行顺序示意图
preHandle (LogInterceptor) → preHandle (AuthInterceptor) → Controller →
postHandle (AuthInterceptor) → postHandle (LogInterceptor) →
视图渲染 → afterCompletion (AuthInterceptor) → afterCompletion (LogInterceptor)
❗ 第五章:避坑指南 & 高频问题
1️⃣ Q:Interceptor未生效?
- 检查点:
- 拦截路径是否匹配(如/api/**覆盖目标接口)。
- 是否被excludePathPatterns排除。
- Spring Boot是否扫描到配置类。
2️⃣ Q:如何获取Spring管理的Bean?
- 方案:Interceptor本身由Spring管理,可直接@Autowired注入Bean。
@Component
public class AuthInterceptor implements HandlerInterceptor {
@Autowired
private UserService userService; // 直接注入
}
3️⃣ Q:Interceptor与Filter的执行顺序?
- 执行顺序:Filter → Interceptor → Controller → Interceptor → Filter
4️⃣ Q:如何中断请求并返回JSON?
@Override
public boolean preHandle(...) {
response.setContentType("application/json");
response.getWriter().write("{\"code\":403, \"msg\":\"无权访问\"}");
return false; // 中断请求
}
🌟 第六章:最佳实践与设计原则
1️⃣ 职责单一化
- 每个Interceptor只做一件事:如鉴权、日志、参数校验分开实现。
2️⃣ 性能优化
- 避免阻塞操作:如远程调用应异步处理,或使用@Async。
- 精简preHandle逻辑:快速拦截非法请求,减少资源消耗。
3️⃣ 动态配置
结合配置中心(如Nacos)动态启用/禁用拦截器:
@Autowired
private AuthInterceptor authInterceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {
if (config.isAuthEnabled()) {
registry.addInterceptor(authInterceptor);
}
}
📌 总结:Interceptor vs. Filter vs. AOP
维度 | Interceptor | Filter | AOP |
---|---|---|---|
作用层级 | Spring MVC层 | Servlet层 | 业务层 |
访问数据 | 可获取HandlerMethod、ModelAndView | 仅处理ServletRequest/Response | 可拦截方法调用、修改参数 |
依赖注入 | 支持 | 需借助DelegatingFilterProxy | 支持 |
适用场景 | Web请求预处理、后处理 | 全局编码、跨域、安全过滤 | 事务、日志、性能监控 |
黄金法则:
- Web层通用逻辑 → Interceptor
- 底层请求/响应处理 → Filter
- 业务层横切关注点 → AOP
📢 互动话题:你在使用Interceptor时踩过哪些坑?或者有更高阶的玩法?评论区等你分享!👇