核心问题:
没登录也能访问系统 → 不安全
目标:登录成功发 token;后续请求必须带 token;后端统一拦截校验 token
1)登录接口(/login)
做什么
- 本质就是查询:
select * from emp where username=? and password=? - 成功返回:
id/username/name/token
关键实现
LoginController:POST /login,@RequestBody EmpEmpService.login():查到员工 → 生成 JWT → 返回LoginInfoEmpMapper:按 username+password 查询
✅ 复习口诀:查库成功 → 生成JWT → 返回给前端存 localStorage
2)为什么需要登录校验(HTTP 无状态)
-
HTTP 每次请求独立,后端不知道你之前是否登录
-
所以要做:
- 登录成功后“存一个标记” (token)
- 后续请求统一拦截校验(Filter/Interceptor)
3)会话跟踪三种方案(记优缺点就行)
Cookie(客户端)
- 自动携带,但:不安全 / 可禁用 / 不能跨域 / 移动端不友好
Session(服务端,底层还是 Cookie)
- 相对安全,但:集群下会话不共享(请求打到不同服务器就丢)
Token(主流)
- 登录成功返回 token,后续请求带 token(请求头)
- 跨端、跨域、支持集群、服务器压力小
- 缺点:需要自己实现生成/校验
✅ 面试回答:企业里基本用 Token/JWT
4)JWT(你必须掌握的点)
JWT是什么
Header.Payload.Signature- Payload 可放自定义数据(id/username)
- Signature 防篡改
- 有 过期时间 exp
两个关键动作
-
生成:
JwtUtils.generateJwt(claims) -
解析校验:
JwtUtils.parseJWT(token)- 解析报错 = 被篡改/过期/非法
✅ 口诀:密钥一致才解析得过;任意改一位就失败;过期也失败
5)登录成功下发 token(项目落地)
-
login 成功后:
claims.put("id", ...)claims.put("username", ...)token = JwtUtils.generateJwt(claims)- 返回给前端
-
前端存:localStorage
-
后续请求:请求头携带
token
6)统一拦截校验(两选一:Filter 或 Interceptor)
A. Filter(Servlet 层,拦截所有资源)
实现步骤:
- 获取 URL
- 如果是
/login→ 放行 - 取 header:
token - token 为空 →
401 - token 解析失败 →
401 - 放行:
chain.doFilter()
特点:
- 拦截范围更大(所有资源)
- 配置:
@WebFilter("/*") + @ServletComponentScan
B. Interceptor(Spring 层,只拦 Controller)
实现逻辑一样,写在 preHandle:
- 返回
true放行,false拦截 - 在
WebMvcConfigurer#addInterceptors注册 - 可用
excludePathPatterns("/login")更优雅(不用自己判断 url.contains)
✅ 实战建议:用 Interceptor 更常见更顺手(只管 Controller)
预期效果
- 没登录访问任意业务接口 → 401 → 前端跳登录页
- 登录成功拿到 token → 后续请求都带 token → 正常访问
3 个练习小目标(按顺序)
- 登录成功能返回 token(Apifox 能看到 token)
- 浏览器 localStorage 存 token,请求头自动带 token
- 拦截器/过滤器能挡住“没 token / token 过期 / token 被篡改”的请求(401)