md_files/自学/草稿.md

6.0 KiB
Raw Blame History

下面从架构、扩展性、安全性、管理成本等几个维度,对 SessionJWT 进行对比,帮助你根据场景选择合适的方案。


一、基本原理

特性 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

// 登录时创建 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

// 生成 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:更灵活、易扩展,适合分布式架构、多端场景,但需要更复杂的设计与安全防护。

根据你的项目架构、团队经验和安全需求,选择最合适的方案即可。