登录功能
- 本质是数据库查询操作:根据用户名和密码查询员工信息。
- 联调测试要求:只有登录成功的员工才能访问后台系统数据(如员工、部门、报表等接口)。
登录校验机制
- 已登录 → 允许访问受保护的接口
- 未登录 → 返回错误码(如
401 Unauthorized),前端跳转至登录页
核心挑战
- HTTP 是无状态协议,无法自动保留登录状态。
- 解决方案:
- 会话跟踪技术:保存登录凭证(如 Token)
- 统一拦截机制:避免在每个接口重复写校验逻辑(使用 Filter 或 Interceptor)
会话跟踪技术对比
| 方案 | 原理 | 优点 | 缺点 |
|---|---|---|---|
| Cookie | 数据存于浏览器,通过请求/响应头传递 | HTTP 原生支持 | 移动端 APP 不支持可被禁用或篡改,不安全无法跨域(协议、域名/IP、端口任一不同即跨域) |
| Session | 服务端存储会话数据,通过 Cookie 传递 SessionID | 安全(敏感数据在服务端) | 依赖 Cookie集群部署需共享 Session(如 Redis) |
| Token(主流) | 客户端持有令牌,每次请求携带 | 支持多端(Web、App、小程序)天然适配分布式/微服务架构无服务端状态,减轻内存压力 | 需自行实现生成、解析、刷新逻辑 |
✅ 现代项目推荐:基于 JWT 的 Token 方案
JWT 令牌(JSON Web Token)
结构(三段式,. 分隔,Base64Url 编码)
-
Header:令牌元信息
Json{"alg":"HS256","typ":"JWT"} -
Payload:有效载荷(可自定义用户信息)
json{"id":"1","username":"Tom","exp":1735689600} -
Signature :签名(防篡改)
HMACSHA256(base64UrlEncode(header) + "." + base64UrlEncode(payload), secret)
使用流程
- 生成 :引入
jjwt依赖,使用Jwts.builder()构建 - 校验 :使用
Jwts.parser().setSigningKey(secret).parseClaimsJws(token) - 关键点 :生成与校验必须使用相同的密钥
⚠️ 注意:Payload 可被解码,切勿存放敏感信息(如密码)
过滤器(Filter)
特点
- JavaWeb 三大组件之一(Servlet、Filter、Listener)
- 拦截所有进入容器的请求(包括静态资源、错误页等)
- 适用于通用底层处理(编码、CORS、日志、鉴权)
开发步骤
- 实现
Filter接口(重写doFilter) - 添加
@WebFilter(urlPatterns = "/*") - Spring Boot 启动类加
@ServletComponentScan
令牌校验逻辑
text
if (路径包含 /login) → 放行
else:
从 Header 获取 token
if (token 为空 或 解析失败) → 返回 401
else → 放行
拦截路径规则(Servlet 规范)
| urlPatterns | 含义 | 示例 |
|---|---|---|
/login |
精确匹配 | 仅拦截 /login |
/api/* |
一级子路径 | 匹配 /api/user,不匹配 /api/user/1 |
/* |
所有一级路径 | 匹配 /home,不匹配 /home/detail |
/** |
所有路径(任意层级) | 匹配 /a/b/c |
过滤器链
- 多个 Filter 按注册顺序执行
- 执行流程:
F1前 → F2前 → 目标资源 → F2后 → F1后
拦截器(Interceptor)
特点
- Spring 框架提供,仅拦截 Spring MVC 控制器请求
- 可注入 Spring Bean,适合业务逻辑(如权限、日志)
开发步骤
- 实现
HandlerInterceptor:preHandle():Controller 前postHandle():Controller 后(视图渲染前)afterCompletion():请求完全结束(前后端分离中通常不用)
- 注册到配置类:
java
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Autowired
private AuthInterceptor authInterceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(authInterceptor)
.addPathPatterns("/**")
.excludePathPatterns("/login", "/static/**");
}
}
拦截路径规则(Spring 风格)
| 路径模式 | 含义 | 示例 |
|---|---|---|
/* |
一级路径 | 匹配 /login,不匹配 /user/1 |
/** |
任意级路径 | 匹配 /user/1/profile |
/api/* |
/api 下一级 |
匹配 /api/login,不匹配 /api/user/1 |
/api/** |
/api 下任意级 |
匹配 /api/user/1 |
✅ 支持
.excludePathPatterns()排除白名单路径
Filter vs Interceptor 对比
| 特性 | Filter | Interceptor |
|---|---|---|
| 所属规范 | Java EE / Servlet | Spring MVC |
| 作用范围 | 所有请求(含静态资源、错误页) | 仅 @Controller 请求 |
| 执行时机 | DispatcherServlet 之前 | DispatcherServlet 之后 |
| Spring Bean 注入 | ❌ 默认不支持 | ✅ 支持 |
| 方法粒度感知 | ❌ 无法获取 Controller 方法 | ✅ 可通过 HandlerMethod 获取 |
| 适用场景 | 底层通用处理(编码、安全头) | 业务逻辑(鉴权、日志) |
使用建议
- 优先使用 Interceptor:Spring Boot 项目更易集成业务逻辑
- 必要时使用 Filter :处理非 Spring 资源(如
/error、静态文件)或底层协议操作
📌 示例:
- 统一字符编码 →
CharacterEncodingFilter(Filter)- 用户登录状态校验 → 自定义 Interceptor
实际应用流程
- 登录接口
- 验证用户名/密码 → 生成 JWT → 返回
{ token: "xxx" }
- 验证用户名/密码 → 生成 JWT → 返回
- 后续请求
- 前端在 Header 携带:
Authorization: Bearer <token>
- 前端在 Header 携带:
- 服务端拦截校验
- 白名单路径(如
/login)→ 直接放行 - 其他路径 → 校验 token 合法性 → 合法则放行,否则返回 401
- 白名单路径(如
补充说明(查漏补缺)
1. JWT 安全最佳实践
- 不要存储敏感信息:Payload 可被 Base64 解码
- 设置合理过期时间:如 Access Token 2 小时,配合 Refresh Token
- 密钥管理:使用高强度密钥,避免硬编码,推荐从配置中心读取
2. Refresh Token 机制(进阶)
- Access Token:短期有效(如 30 分钟),用于 API 访问
- Refresh Token:长期有效(如 7 天),用于换取新 Access Token
- 提升安全性,减少用户频繁登录
3. 前端 Token 存储建议
- 避免 localStorage:易受 XSS 攻击
- 推荐方案 :
- 内存存储(页面刷新丢失,需配合 Refresh Token)
httpOnlyCookie(防 XSS,但需处理 CSRF)
4. 拦截器与过滤器执行顺序(同时存在)
text
请求 → Filter1 → Filter2 → DispatcherServlet → Interceptor1 → Controller
→ Interceptor1后 → Filter2后 → Filter1后 → 响应
5. 务必排除的路径
- 登录/注册接口:
/login,/register - 静态资源:
/static/**,/favicon.ico - 健康检查:
/actuator/health(Spring Boot)
6. JWT 替代方案(了解)
- Opaque Token:令牌为随机字符串,服务端查数据库验证(如 OAuth2)
- Stateless Session:结合加密 Cookie 存储用户信息(如 Spring Session + JWT)