-
Token、Session、Cookie、JWT、OAuth2:一文给你彻底讲透!
- 网站名称:Token、Session、Cookie、JWT、OAuth2:一文给你彻底讲透!
- 网站分类:技术文章
- 收录时间:2025-09-14 16:09
- 网站地址:
“Token、Session、Cookie、JWT、OAuth2:一文给你彻底讲透!” 网站介绍
大家好!我是谦!今天给大家分享几个常见又容易混淆的概念!
发现小伙伴们,对Token、Session、Cookie、JWT、OAuth2这些概念非常容易搞混。
有些小伙伴在工作中可能会遇到过这样的困惑:
- 做登录功能时,到底该用Session还是JWT?
- OAuth2和Token是什么关系?
- 为什么有的方案要把Token存在Cookie里?
今天这篇文章就来和小伙伴们一起聊聊这个话题,希望对各位会有所帮助。
一、以餐厅就餐为例开始讲
为了更好地理解,我先用一个餐厅就餐的比喻来解释这些概念:
现在,让我们深入每个概念的技术细节。
二、Cookie:HTTP的世界身份证
2.1 什么是Cookie?
Cookie 是一小段文本信息,由服务器通过 HTTP 响应头中的 Set-Cookie字段发送至浏览器,并由浏览器存储。随后,在每一次对该服务器的后续 HTTP 请求中,浏览器都会自动通过 Cookie请求头将其回传至服务器。
工作原理:
2.2 Cookie实战代码
// 服务器设置Cookie
@PostMapping("/login")
public ResponseEntity login(@RequestBody User user, HttpServletResponse response) {
if (authService.authenticate(user)) {
Cookie cookie = new Cookie("session_id", generateSessionId());
cookie.setMaxAge(3600); // 1小时有效期
cookie.setHttpOnly(true); // 防止XSS攻击
cookie.setSecure(true); // 仅HTTPS传输
cookie.setPath("/"); // 对整个站点有效
response.addCookie(cookie);
return ResponseEntity.ok().build();
}
return ResponseEntity.status(401).build();
}
// 读取Cookie
@GetMapping("/profile")
public ResponseEntity getProfile(@CookieValue("session_id") String sessionId) {
User user = sessionService.getUserBySession(sessionId);
return ResponseEntity.ok(user);
}
2.3 Cookie的重要属性
属性 | 作用 | 安全建议 |
HttpOnly | 防止JavaScript访问 | 必须设置为true,防XSS |
Secure | 仅通过HTTPS传输 | 生产环境必须设置为true |
SameSite | 控制跨站请求时是否发送Cookie | 建议设置为Strict或Lax |
Max-Age | 设置Cookie有效期 | 根据业务安全性要求设置 |
三、Session:服务端的用户档案
3.1 什么是Session?
Session 是用于在服务器端存储用户会话状态信息的机制。服务器会为每个会话分配一个唯一的 Session ID,并通过 Set-Cookie 字段将该 ID 下发至浏览器。浏览器在后续请求中自动携带此 ID,服务器便可通过此 ID 识别并还原用户的会话状态。
Session存储结构:
// 典型的Session数据结构
public class UserSession {
private String sessionId;
private String userId;
private String username;
private Date loginTime;
private Date lastAccessTime;
private Map<String, Object> attributes; // 自定义属性
// 省略getter/setter
}
3.2 Session实战代码
// 基于Spring Session的实现
@PostMapping("/login")
public String login(@RequestParam String username,
@RequestParam String password,
HttpSession session) {
User user = userService.authenticate(username, password);
if (user != null) {
// 将用户信息存入Session
session.setAttribute("currentUser", user);
session.setAttribute("loginTime", new Date());
return"redirect:/dashboard";
}
return"login?error=true";
}
@GetMapping("/dashboard")
public String dashboard(HttpSession session) {
// 从Session获取用户信息
User user = (User) session.getAttribute("currentUser");
if (user == null) {
return"redirect:/login";
}
return"dashboard";
}
3.3 Session的存储方案
1. 内存存储(默认)
# application.yml
server:
servlet:
session:
timeout: 1800 # 30分钟过期时间
2. Redis分布式存储
@Configuration
@EnableRedisHttpSession // 启用Redis Session存储
public class SessionConfig {
@Bean
public LettuceConnectionFactory connectionFactory() {
return new LettuceConnectionFactory();
}
}
3. Session集群同步问题
四、Token:去中心化的身份令牌
4.1 什么是Token?
Token 是一种自包含的、无状态的身份验证令牌,服务器无需在服务端存储会话状态信息,所有用于身份验证和授权的必要数据均被编码并包含在 Token 内部。
Token 与 Session 的核心区别如下:
4.2 Token实战代码
// 生成Token
public String generateToken(User user) {
long currentTime = System.currentTimeMillis();
return JWT.create()
.withIssuer("myapp") // 签发者
.withSubject(user.getId()) // 用户ID
.withClaim("username", user.getUsername())
.withClaim("role", user.getRole())
.withIssuedAt(new Date(currentTime)) // 签发时间
.withExpiresAt(new Date(currentTime + 3600000)) // 过期时间
.sign(Algorithm.HMAC256(secret)); // 签名密钥
}
// 验证Token
public boolean validateToken(String token) {
try {
JWTVerifier verifier = JWT.require(Algorithm.HMAC256(secret))
.withIssuer("myapp")
.build();
DecodedJWT jwt = verifier.verify(token);
returntrue;
} catch (JWTVerificationException exception) {
returnfalse;
}
}
五、JWT:现代化的Token标准
5.1 什么是JWT?
JWT(JSON Web Token)是一种开放标准(RFC 7519),用于在各方之间安全地传输信息作为JSON对象。
这种信息可以被验证和信任,因为它是数字签名的。
JWT结构:
header.payload.signature
解码示例:
// Header
{
"alg": "HS256",
"typ": "JWT"
}
// Payload
{
"sub": "1234567890",
"name": "John Doe",
"iat": 1516239022,
"exp": 1516242622
}
// Signature
HMACSHA256(
base64UrlEncode(header) + "." +
base64UrlEncode(payload),
secret)
5.2 JWT实战代码
// 创建JWT
public String createJWT(User user) {
return Jwts.builder()
.setHeaderParam("typ", "JWT")
.setSubject(user.getId())
.setIssuer("myapp")
.setIssuedAt(new Date())
.setExpiration(new Date(System.currentTimeMillis() + 3600000))
.claim("username", user.getUsername())
.claim("role", user.getRole())
.signWith(SignatureAlgorithm.HS256, secret.getBytes())
.compact();
}
// 解析JWT
public Claims parseJWT(String jwt) {
return Jwts.parser()
.setSigningKey(secret.getBytes())
.parseClaimsJws(jwt)
.getBody();
}
// 在Spring Security中使用JWT
@Component
publicclass JwtFilter extends OncePerRequestFilter {
@Override
protected void doFilterInternal(HttpServletRequest request,
HttpServletResponse response,
FilterChain chain) {
String token = resolveToken(request);
if (token != null && validateToken(token)) {
Authentication auth = getAuthentication(token);
SecurityContextHolder.getContext().setAuthentication(auth);
}
chain.doFilter(request, response);
}
}
5.3 JWT的最佳实践
1. 安全存储
// 前端安全存储方案
// 不推荐:localStorage(易受XSS攻击)
// 推荐:HttpOnly Cookie(防XSS)或内存存储
2. 令牌刷新机制
// 双Token机制:Access Token + Refresh Token
publicclass TokenPair {
private String accessToken; // 短期有效:1小时
private String refreshToken; // 长期有效:7天
}
// 刷新令牌接口
@PostMapping("/refresh")
public ResponseEntity refresh(@RequestBody RefreshRequest request) {
String refreshToken = request.getRefreshToken();
if (validateRefreshToken(refreshToken)) {
String userId = extractUserId(refreshToken);
String newAccessToken = generateAccessToken(userId);
return ResponseEntity.ok(new TokenPair(newAccessToken, refreshToken));
}
return ResponseEntity.status(401).build();
}
六、OAuth 2.0:授权框架之王
6.1 什么是OAuth 2.0?
OAuth 2.0是一个授权框架,允许第三方应用在获得用户授权后,代表用户访问受保护的资源。
OAuth 2.0角色:
- 资源所有者(Resource Owner):用户
- 客户端(Client):第三方应用
- 授权服务器(Authorization Server):颁发访问令牌
- 资源服务器(Resource Server):托管受保护资源
6.2 OAuth 2.0授权码流程
6.3 OAuth 2.0实战代码
// Spring Security OAuth2配置
@Configuration
@EnableAuthorizationServer
publicclass AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {
@Autowired
private AuthenticationManager authenticationManager;
@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.inMemory()
.withClient("clientapp")
.secret(passwordEncoder.encode("123456"))
.authorizedGrantTypes("authorization_code", "refresh_token")
.scopes("read", "write")
.redirectUris("http://localhost:8080/callback");
}
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) {
endpoints.authenticationManager(authenticationManager)
.tokenStore(tokenStore())
.accessTokenConverter(accessTokenConverter());
}
}
// 资源服务器配置
@Configuration
@EnableResourceServer
publicclass ResourceServerConfig extends ResourceServerConfigurerAdapter {
@Override
public void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/api/public/**").permitAll()
.antMatchers("/api/private/**").authenticated()
.antMatchers("/api/admin/**").hasRole("ADMIN");
}
}
七、五大概念对比
为了能家更清晰地理解这五个概念的关系和区别,我准备了以下对比表格:
7.1 功能定位对比
概念 | 本质 | 存储位置 | 主要用途 | 特点 |
Cookie | HTTP状态管理机制 | 浏览器 | 维持会话状态 | 自动携带,有大小限制 |
Session | 服务端会话信息 | 服务器 | 存储用户状态 | 服务端状态,需要存储管理 |
Token | 访问凭证 | 客户端/服务端 | 身份认证 | 自包含,可验证 |
JWT | Token的一种实现标准 | 客户端/服务端 | 安全传输信息 | 标准化,自包含,可签名 |
OAuth2 | 授权框架 | 不直接存储 | 第三方授权 | 标准化授权流程 |
7.2 应用场景对比
场景 | 推荐方案 | 原因说明 |
传统Web应用 | Session + Cookie | 简单易用,生态成熟 |
前后端分离应用 | JWT | 无状态,适合API认证 |
第三方登录 | OAuth 2.0 | 标准化授权,安全可靠 |
微服务架构 | JWT | 分布式认证,无需会话同步 |
移动端应用 | Token | 轻量级,适合移动网络 |
7.3 安全考虑对比
安全威胁 | Cookie方案防护 | Token/JWT方案防护 |
XSS攻击 | HttpOnly Cookie | 避免localStorage存储 |
CSRF攻击 | SameSite Cookie | 自定义Header+CSRF Token |
令牌泄露 | 短期有效+HTTPS | 短期有效+HTTPS+刷新机制 |
数据篡改 | 服务端验证 | 签名验证 |
总结
通过今天的深入探讨,我们可以得出以下结论:
- Cookie 是载体:作为 HTTP 协议的状态管理机制,它是 Session 和 Token 的一种重要传输媒介。
- Session 是状态:指在服务器端维护的用户会话状态信息,通常需要借助 Cookie 或 URL 重写实现状态保持。
- Token 是凭证:是一种用于身份验证与授权的凭证,可存放于 Cookie、HTTP 头部或 URL 中。
- JWT 是标准:代表一种 Token 的标准化实现方式,设计自包含、可验证且可信任。
- OAuth 2.0 是框架:是一套完整的第三方授权框架,明确了标准的授权流程与交互方式。
最终建议如下:
- 简单 Web 应用可采用:Session + Cookie
- 前后端分离架构推荐:JWT + HTTP Header
- 需接入第三方授权时使用:OAuth 2.0 + JWT
没有绝对最优的方案,只有最适合具体业务场景的选择。
更多相关网站
- 高效使用Java构建工具,Maven篇|云效工程师指北
- CBN丨China's consumer prices hold steady in November
- 胆小的跳蛛利用天敌蚂蚁作保镖逃离毒蜘蛛追杀
- Spring Boot 私有文件保护:签名 URL + 权限控制 + 限流一体化方案
- Spring Boot 企业级应用与微服务实战指南
- React 19 + React-Router v7 超级详细实用、好理解的优雅动态路由懒加
- Alibaba Leads $60 Million Series B Round in AI Video Startup AISphere
- 基于 Vue3+Vite+Antd 企业级中后台管理
- Maven 使用说明和配置_maven配置详解
- AI Agents Could Replace Apps Entirely, Says Ant Group CEO
- Shanghai blockchain park proves WAIC's worth
- 数据治理(十二):Ranger2.1.0 源码编译
- CBN丨China pledges expanded market access for foreign investors
- Spring Boot 2.x → 3.x 实战迁移
- vue-antd后台管理系统_vue ant
- Conference on the Bund: young innovators shine as China's next tech generation
- JD.com Drives Robotics Funding Frenzy With Investments in LimX Dynamics, Spirit AI, and EngineAI
- Remarks by H.E. Xi Jinping
- 最近发表
- 标签列表
-
- mydisktest_v298 (35)
- sql 日期比较 (33)
- document.appendchild (35)
- 头像打包下载 (35)
- 梦幻诛仙表情包 (36)
- java面试宝典2019pdf (26)
- disk++ (30)
- 加密与解密第四版pdf (29)
- iteye (26)
- centos7.4下载 (32)
- intouch2014r2sp1永久授权 (33)
- jdk1.8.0_191下载 (27)
- axure9注册码 (30)
- 兔兔工程量计算软件下载 (27)
- ccproxy破解版 (31)
- aida64模板 (28)
- engine=innodb (33)
- shiro jwt (28)
- segoe ui是什么字体 (27)
- head first java电子版 (32)
- clickhouse中文文档 (28)
- jdk-8u181-linux-x64.tar.gz (32)
- 计算机网络自顶向下pdf (34)
- -dfile.encoding=utf-8 (33)
- jdk1.9下载 (32)