md_files/自学/草稿.md

144 lines
6.0 KiB
Markdown
Raw Normal View History

下面从架构、扩展性、安全性、管理成本等几个维度,对 **Session****JWT** 进行对比,帮助你根据场景选择合适的方案。
------
## 一、基本原理
| 特性 | Session | JWTJSON Web Token |
| -------- | ------------------------------------ | ----------------------------------------------- |
| 存储方式 | 服务端存储会话数据如内存、Redis | 客户端存储完整的令牌(通常在 Header 或 Cookie |
| 标识方式 | 客户端持有一个 Session ID | 客户端持有一个自包含的 Token |
| 状态管理 | 有状态Stateful服务器要维护会话 | 无状态Stateless服务器不存会话 |
------
## 二、对比分析
### 1. 架构与扩展性
- **Session**
- 单体应用:内存中维护 Map<sessionId, userData>,简单易用。
- 分布式/集群:需要共享 Session如 Redis、数据库、Sticky Session增加运维成本。
- **JWT**
- 无状态:令牌自带用户信息及签名,服务器只需校验签名即可,无需存储。
- 分布式友好:各节点只要共享签名密钥(或公钥),即可校验,无需集中存储。
### 2. 性能
- **Session**
- 每次请求都要从存储(内存/Redis/DB读取会话数据IO 成本或网络开销。
- 并发高时,集中式 Session 存储可能成为瓶颈。
- **JWT**
- 校验签名HMAC 或 RSA为 CPU 操作,无网络开销,性能开销较小。
- 但 Token 通常更大(包含多段 Base64每次请求都要传输带宽略增。
### 3. 安全性
- **Session**
- 会话数据保存在服务器端,客户端只能拿到 Session ID敏感数据不暴露。
- 可在服务器端随时销毁或更新 Session强制登出、权限变更即时生效
- **JWT**
- 令牌自包含所有声明claims如果存敏感数据需加密JWE否则仅签名JWS也可能泄露信息。
- 无法主动撤销(除非做黑名单),需要控制有效期并结合“刷新令牌”机制。
### 4. 可控性与管理
- **Session**
- **可控性强**:服务器可随时作废 Session适合需要即时注销、权限动态调整的场景。
- 过期策略灵活:可按用户、按应用统一配置。
- **JWT**
- **可控性弱**Token 一旦签发,在到期前无法从服务器强制失效(除非额外维护黑名单)。
- 需要设计“短生命周期 + 刷新令牌”模式,增加实现复杂度。
### 5. 跨域与移动端
- **Session**
- 依赖 Cookie同源策略跨域或移动端原生 App使用受限。
- 跨域时需配合 CORS + `withCredentials`,且浏览器必须支持并开启 Cookie。
- **JWT**
- 与 HTTP 协议无关,既可放在 Authorization 头,也可放在 URL、LocalStorage移动端/第三方客户端更友好。
- 只要客户端能发送 HTTP Header就能携带 Token。
### 6. 实现复杂度
- **Session**
- 框架通常开箱即用(如 Spring Session开发者只需开启即可。
- 自动处理过期、失效,管理简单。
- **JWT**
- 需要设计签名算法、密钥管理、过期策略、刷新机制、黑名单等。
- 容易因配置不当造成安全漏洞算法降级、密钥泄露、Token 劫持等)。
------
## 三、何时选用
| 场景类型 | 推荐方案 | 原因 |
| --------------------------- | -------- | ---------------------------------------------------------- |
| 单体 Web 应用、后台管理系统 | Session | 简单、可控、安全性高,框架支持完善。 |
| 分布式微服务、无状态 API | JWT | 无需集中存储,易扩展;移动端/第三方客户端友好。 |
| 高度安全、需即时失效场景 | Session | 可随时在服务器端销毁会话,确保强制登出或权限变更即时生效。 |
| 跨域或多端Web + App | JWT | Token 可在多种客户端轻松传递,无需依赖浏览器 Cookie。 |
------
## 四、示例代码
### Session 示例Spring Boot
```java
// 登录时创建 Session
@PostMapping("/login")
public String login(HttpServletRequest req, @RequestParam String user, @RequestParam String pass) {
if (authService.verify(user, pass)) {
req.getSession().setAttribute("userId", user);
return "登录成功";
}
return "登录失败";
}
// 受保护资源
@GetMapping("/profile")
public User profile(HttpServletRequest req) {
String userId = (String) req.getSession().getAttribute("userId");
return userService.findById(userId);
}
```
### JWT 示例Spring Boot + jjwt
```java
// 生成 Token
@PostMapping("/login")
public String login(@RequestParam String user, @RequestParam String pass) {
if (authService.verify(user, pass)) {
return Jwts.builder()
.setSubject(user)
.setExpiration(new Date(System.currentTimeMillis() + 3600_000))
.signWith(SignatureAlgorithm.HS256, secretKey)
.compact();
}
throw new UnauthorizedException();
}
// 过滤器中校验
@Override
protected void doFilterInternal(HttpServletRequest req, HttpServletResponse res, FilterChain chain) {
String token = req.getHeader("Authorization");
if (token != null && token.startsWith("Bearer ")) {
String user = Jwts.parser().setSigningKey(secretKey)
.parseClaimsJws(token.substring(7))
.getBody().getSubject();
// 将 user 存入 SecurityContext …
}
chain.doFilter(req, res);
}
```
------
## 五、结论
- **Session**:上手简单、安全可控,适合绝大多数传统 Web 应用。
- **JWT**:更灵活、易扩展,适合分布式架构、多端场景,但需要更复杂的设计与安全防护。
根据你的项目架构、团队经验和安全需求,选择最合适的方案即可。