1. Session
(1)定义
- Session 是一种服务器端的会话管理机制,通过在服务器存储用户状态来实现身份认证。
(2)工作原理
- 用户登录后,服务器生成一个唯一的 Session ID,并将其存储在服务器内存或数据库中。
- 服务器将 Session ID 通过 Cookie 返回给客户端。
- 客户端在后续请求中携带 Session ID(
可通过cookie或url携带
),服务器通过 Session ID 查找用户状态。
(3)优点
- 安全性高:Session 数据存储在服务器端,客户端无法篡改。
- 灵活性:可以存储任意类型的数据(如用户权限、登录时间)。
(4)缺点
- 扩展性差:在分布式系统中,需要共享 Session 数据(如使用 Redis)。
- 性能开销:每次请求都需要查询 Session 数据,增加服务器负担。
(5)适用场景
- 传统单体应用(
分布式场景sessionID不能通过cookie传递,且服务端要实现session数据共享和一致性保持
)。 - 需要存储复杂用户状态的场景。
2. Token
(1)定义
- Token 是一种客户端持有的凭证,通常是一个随机字符串,用于标识用户身份。
(2)工作原理
- 用户登录后,服务器生成一个 Token 并返回给客户端。
- 客户端在后续请求中携带 Token(通常放在 HTTP Header 中)。
- 服务器验证 Token 的有效性,并返回请求结果。
(3)优点
- 无状态:服务器不需要存储 Token 数据,适合分布式系统。
- 扩展性强:Token 可以存储少量用户信息(如用户 ID)。
(4)缺点
- 安全性依赖实现:Token 需要加密或签名,防止伪造。
- 无法主动失效:除非服务器维护一个黑名单,否则 Token 在过期前一直有效。
(5)适用场景
- 分布式系统。
- 需要无状态认证的场景。
3. JWT(JSON Web Token)
(1)定义
- JWT 是一种基于 JSON 的开放标准(RFC 7519),用于在客户端和服务器之间安全地传输信息。
(2)工作原理
- 用户登录后,服务器生成一个 JWT 并返回给客户端。
- 客户端在后续请求中携带 JWT(通常放在 HTTP Header 中)。
- 服务器验证 JWT 的签名,并解析其中的用户信息。
(3)结构
JWT 由三部分组成,用 .
分隔:
- Header:描述算法和类型(如
{"alg": "HS256", "typ": "JWT"}
)。 - Payload:存储用户信息(如
{"sub": "123", "name": "John"}
)。 - Signature:对 Header 和 Payload 的签名,用于验证完整性。
(4)优点
- 自包含:JWT 包含所有必要信息,减少数据库查询。
- 跨语言支持:JWT 是标准化的,支持多种编程语言。
- 适合分布式系统:无需服务器存储会话数据。
(5)缺点
- 无法主动失效:JWT 在过期前一直有效,除非维护黑名单。
- 数据暴露:Payload 是 Base64 编码的,可以被解码(但不加密)。
(6)适用场景
- 分布式系统和微服务架构。
- 需要跨域认证的场景(如单点登录)。
4. 三者的对比
特性 | Session | Token | JWT |
---|---|---|---|
存储位置 | 服务器端 | 服务器端或客户端 | 客户端 |
状态管理 | 有状态 | 无状态 | 无状态 |
数据存储 | 服务器内存或数据库 | 随机字符串 | JSON 数据(Base64 编码) |
安全性 | 高(数据在服务器端) | 依赖实现 | 依赖签名算法 |
扩展性 | 差(需共享 Session 数据) | 强 | 强 |
性能开销 | 高(每次请求查询 Session) | 低 | 低 |
适用场景 | 单体应用 | 分布式系统 | 分布式系统、跨域认证 |
5. 示例
Java 示例:JWT 生成与验证
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.security.Keys;
import java.security.Key;
import java.util.Date;
public class JwtExample {
// 密钥(用于签名和验证 JWT)
private static final Key SECRET_KEY = Keys.secretKeyFor(SignatureAlgorithm.HS256);
public static void main(String[] args) {
// 生成 JWT
String jwt = generateJwt("123", "John", 3600); // 1小时有效期
System.out.println("Generated JWT: " + jwt);
// 验证并解析 JWT
Claims claims = parseJwt(jwt);
if (claims != null) {
System.out.println("User ID: " + claims.get("user_id"));
System.out.println("Username: " + claims.get("username"));
} else {
System.out.println("Invalid JWT");
}
}
// 生成 JWT
public static String generateJwt(String userId, String username, int expirationSeconds) {
return Jwts.builder()
.claim("user_id", userId) // 自定义声明
.claim("username", username)
.setIssuedAt(new Date()) // 签发时间
.setExpiration(new Date(System.currentTimeMillis() + expirationSeconds * 1000)) // 过期时间
.signWith(SECRET_KEY) // 签名
.compact();
}
// 解析并验证 JWT
public static Claims parseJwt(String jwt) {
try {
return Jwts.parserBuilder()
.setSigningKey(SECRET_KEY)
.build()
.parseClaimsJws(jwt)
.getBody();
} catch (Exception e) {
System.err.println("JWT validation failed: " + e.getMessage());
return null;
}
}
}
Java 示例:Session 管理
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
public class SessionExample {
public static void main(String[] args) {
// 模拟 HttpServletRequest
HttpServletRequest request = new MockHttpServletRequest();
// 创建 Session
HttpSession session = request.getSession();
session.setAttribute("user_id", "123");
session.setAttribute("username", "John");
// 获取 Session 数据
String userId = (String) session.getAttribute("user_id");
String username = (String) session.getAttribute("username");
System.out.println("User ID: " + userId);
System.out.println("Username: " + username);
// 销毁 Session
session.invalidate();
}
}
// 模拟 HttpServletRequest
class MockHttpServletRequest implements HttpServletRequest {
private HttpSession session = new MockHttpSession();
@Override
public HttpSession getSession() {
return session;
}
// 其他方法省略
}
// 模拟 HttpSession
class MockHttpSession implements HttpSession {
private java.util.Map<String, Object> attributes = new java.util.HashMap<>();
@Override
public void setAttribute(String name, Object value) {
attributes.put(name, value);
}
@Override
public Object getAttribute(String name) {
return attributes.get(name);
}
@Override
public void invalidate() {
attributes.clear();
}
// 其他方法省略
}
Java 示例:Token 认证
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
public class TokenExample {
// 模拟 Token 存储
private static final Map<String, String> TOKEN_STORE = new HashMap<>();
public static void main(String[] args) {
// 用户登录,生成 Token
String token = generateToken("123", "John");
System.out.println("Generated Token: " + token);
// 验证 Token
String userId = validateToken(token);
if (userId != null) {
System.out.println("User ID: " + userId);
} else {
System.out.println("Invalid Token");
}
}
// 生成 Token
public static String generateToken(String userId, String username) {
String token = UUID.randomUUID().toString();
TOKEN_STORE.put(token, userId); // 存储 Token 和用户 ID
return token;
}
// 验证 Token
public static String validateToken(String token) {
return TOKEN_STORE.getOrDefault(token, null);
}
}
总结
- Session:适合传统单体应用,安全性高但扩展性差。
- Token:适合分布式系统,无状态但安全性依赖实现(
相比session解决了跨域问题,服务端存储问题,频繁查询问题
)。 - JWT:适合分布式系统和跨域认证,自包含但无法主动失效(
相比token,允许存储更多的用户消息,进一步降低了查询开销
)。
3种认证方式无好坏之分,根据系统架构及业务需求选择合适的认证机制,可以显著提升系统的安全性和性能。