一、前言:为什么需要登录拦截?
在一个典型的 Web 应用中,我们经常遇到这样的需求:
- 用户未登录时,访问 /user/profile 应自动跳转到登录页
- 管理员才能访问 /admin/* 路径
- 某些接口只允许已认证用户调用(如修改密码、下单)
如果每个 Controller 都手动写 if (session == null),不仅重复、易漏,还难以维护。
解决方案:使用 Spring MVC 拦截器(Interceptor)统一处理!
本文将带你: ✅ 手动实现登录状态拦截 ✅ 精准配置拦截路径与放行规则 ✅ 支持 JSON 接口返回 401(前后端分离场景) ✅ 避开常见陷阱(如静态资源被拦截)
二、核心原理:拦截器 vs 过滤器
| 所属框架 | Spring MVC | Servlet 容器 |
| 能否注入 Bean | ✅ 可以 | ❌ 不行(除非特殊配置) |
| 执行时机 | Controller 方法调用前后 | 请求进入容器时 |
| 是否支持路径匹配 | ✅ 精确(AntPathMatcher) | ❌ 需手动解析 URL |
| 适用场景 | 业务级拦截(如登录、权限) | 编码、日志、安全头等底层处理 |
📌 结论:登录拦截优先使用 Interceptor!
三、实战:基于 Session 的登录拦截器
1. 前提:已有登录逻辑(存 Session)
假设用户登录成功后,已将用户名存入 Session:
// 登录成功时
session.setAttribute("currentUser", "zhangsan");
2. 自定义拦截器
@Component
public class LoginInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response,
Object handler) throws Exception {
// 1. 获取当前会话
HttpSession session = request.getSession(false);
// 2. 判断是否已登录
if (session == null || session.getAttribute("currentUser") == null) {
// 3. 判断是页面请求还是 AJAX 请求
String contentType = request.getHeader("Content-Type");
String accept = request.getHeader("Accept");
boolean isAjax = (contentType != null && contentType.contains("application/json")) ||
(accept != null && accept.contains("application/json"));
if (isAjax) {
// 前后端分离:返回 JSON 错误
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
response.setContentType("application/json;charset=UTF-8");
response.getWriter().write("{\\"code\\":401,\\"msg\\":\\"请先登录\\"}");
return false;
} else {
// 传统 Web:重定向到登录页
response.sendRedirect("/login");
return false;
}
}
// 已登录,放行
return true;
}
}
✅ 智能判断:自动区分页面跳转和 API 调用,返回不同响应!
3. 注册拦截器并配置路径
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Autowired
private LoginInterceptor loginInterceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(loginInterceptor)
// 拦截哪些路径
.addPathPatterns("/user/**", "/order/**", "/profile/**")
// 放行哪些路径(必须放行登录、静态资源等)
.excludePathPatterns(
"/login",
"/doLogin",
"/logout",
"/css/**",
"/js/**",
"/images/**",
"/captcha", // 图形验证码
"/error", // 错误页
"/webjars/**" // Bootstrap 等
);
}
}
🔑 关键点:
- addPathPatterns:指定需要保护的路径
- excludePathPatterns:必须放行登录相关和静态资源,否则页面样式丢失!
四、进阶:支持角色权限拦截(可选)
如果需要区分普通用户和管理员:
// 登录时存入角色
session.setAttribute("role", "admin");
// 拦截器中增强判断
String role = (String) session.getAttribute("role");
if (!"admin".equals(role)) {
response.sendError(403, "无权访问");
return false;
}
或定义多个拦截器:
- LoginInterceptor:只校验是否登录
- AdminInterceptor:校验是否为管理员(应用于 /admin/**)
五、前后端分离场景:纯 API 拦截
如果你的项目是 Vue/React + Spring Boot,所有接口都返回 JSON,可简化拦截器:
@Component
public class ApiLoginInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response,
Object handler) throws Exception {
HttpSession session = request.getSession(false);
if (session == null || session.getAttribute("currentUser") == null) {
response.setStatus(401);
response.setContentType("application/json;charset=UTF-8");
response.getWriter().write("{\\"error\\":\\"Unauthorized\\",\\"message\\":\\"请先登录\\"}");
return false;
}
return true;
}
}
// 配置:拦截所有 /api/** 开头的请求
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new ApiLoginInterceptor())
.addPathPatterns("/api/**")
.excludePathPatterns("/api/auth/login", "/api/public/**");
}
💡 前端收到 401 后,跳转到登录页即可。
六、避坑指南:常见问题与解决方案
❌ 坑 1:静态资源(CSS/JS)被拦截,页面样式错乱
原因:未在 excludePathPatterns 中放行 /css/** 等路径 解决:务必放行所有静态资源目录
❌ 坑 2:登录成功后仍被拦截
原因:Session 未正确创建,或拦截器执行顺序问题 排查:
- 检查 session.setAttribute() 是否执行
- 确保登录接口在 excludePathPatterns 中
❌ 坑 3:拦截器中无法注入其他 Service
原因:拦截器未被 Spring 管理 解决:加上 @Component 注解,并通过 @Autowired 注入
❌ 坑 4:跨域请求导致 Cookie 丢失(前后端分离)
现象:前端携带 withCredentials: true,但后端收不到 JSESSIONID 解决:配置 CORS 允许凭证
@Bean
public CorsConfigurationSource corsConfigurationSource() {
CorsConfiguration config = new CorsConfiguration();
config.setAllowCredentials(true);
config.addAllowedOrigin("http://localhost:8080");
config.addAllowedHeader("*");
config.addAllowedMethod("*");
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", config);
return source;
}
七、替代方案对比
| 自定义 Interceptor | 简单、灵活、可控 | 需手动维护 | 中小型项目 |
| Spring Security | 功能强大、企业级 | 学习成本高 | 大型系统、高安全要求 |
| AOP 切面 | 可按注解拦截 | 无法处理 URL 路径 | 特定方法级控制 |
📌 建议:
- 快速上线 → Interceptor
- 金融/政务系统 → Spring Security
八、结语
感谢您的阅读!如果你有任何疑问或想要分享的经验,请在评论区留言交流!
网硕互联帮助中心


评论前必须登录!
注册