共计 3057 个字符,预计需要花费 8 分钟才能阅读完成。
在微服务架构和前后端分离的现代应用中,传统的 Session 认证机制逐渐暴露出诸多问题。让我们先聊聊为什么需要 Bearer Token?

传统 Session 的局限性
- 服务器状态依赖 :Session 需要服务端存储用户状态,这给水平扩展带来挑战
- 跨域问题 :Cookie 的 Same-Origin 策略限制了跨域 API 调用
- CSRF 风险 :基于 Cookie 的认证天然容易遭受跨站请求伪造攻击
而 Bearer Token 就像一张演唱会门票——谁拿着票谁就能入场,完全不需要服务器记住每个观众。这种无状态特性完美契合 RESTful API 的设计哲学。
核心概念:Bearer Token 的本质
- 与 Basic Auth 对比 :
- Basic Auth 需要每次携带用户名密码(Base64 编码)
-
Bearer Token 是预先颁发的临时凭证,降低了密码泄露风险
-
与 Cookie 对比 :
- Cookie 由浏览器自动管理,受同源策略限制
- Bearer Token 需要手动添加到请求头,适用于任意客户端
标准 HTTP 头示例:
GET /api/user HTTP/1.1
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
两种主流实现方案
JWT (JSON Web Token)
优点 :
– 自包含(包含用户信息和过期时间)
– 减少数据库查询
缺点 :
– 无法主动失效(除非维护黑名单)
– 体积较大
示例结构:
// Header.Payload.Signature
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
随机字符串 Token
优点 :
– 短小精悍
– 服务端可完全控制
缺点 :
– 每次都需要查询数据库
实战代码示例
Spring Boot 实现
@RestController
public class AuthController {@PostMapping("/login")
public ResponseEntity<String> login(@RequestBody LoginRequest request) {
// 1. 验证用户名密码(示例代码,实际需要加密验证)if (!"admin".equals(request.getUsername()) || !"123456".equals(request.getPassword())) {return ResponseEntity.status(401).build();}
// 2. 生成 JWT(使用 jjwt 库)String token = Jwts.builder()
.setSubject(request.getUsername())
.setExpiration(new Date(System.currentTimeMillis() + 3600_000)) // 1 小时过期
.signWith(SignatureAlgorithm.HS256, "your-256-bit-secret".getBytes())
.compact();
// 3. 返回 Token
return ResponseEntity.ok(token);
}
@GetMapping("/profile")
public ResponseEntity<String> profile(@RequestHeader("Authorization") String authHeader) {
// 1. 验证 Bearer Token
if (authHeader == null || !authHeader.startsWith("Bearer")) {return ResponseEntity.status(401).build();}
String token = authHeader.substring(7);
try {
// 2. 解析 JWT
Claims claims = Jwts.parser()
.setSigningKey("your-256-bit-secret".getBytes())
.parseClaimsJws(token)
.getBody();
// 3. 返回用户信息
return ResponseEntity.ok("Hello," + claims.getSubject());
} catch (Exception e) {return ResponseEntity.status(401).build();}
}
}
Node.js Express 实现
const express = require('express');
const jwt = require('jsonwebtoken');
const app = express();
app.post('/login', (req, res) => {
// 模拟用户验证
if (req.body.username !== 'admin' || req.body.password !== '123456') {return res.sendStatus(401);
}
// 生成 Token(有效期 1 小时)const token = jwt.sign({ username: req.body.username},
'your-256-bit-secret',
{expiresIn: '1h'}
);
res.json({token});
});
app.get('/profile', (req, res) => {
// 从 Header 提取 Token
const authHeader = req.headers['authorization'];
if (!authHeader || !authHeader.startsWith('Bearer')) {return res.sendStatus(401);
}
const token = authHeader.split(' ')[1];
try {
// 验证 Token
const decoded = jwt.verify(token, 'your-256-bit-secret');
res.send(`Hello, ${decoded.username}`);
} catch (err) {res.sendStatus(401);
}
});
安全最佳实践
- 必须使用 HTTPS:
- Bearer Token 在明文传输中极容易被窃取
-
使用 Let’s Encrypt 免费证书
-
合理的过期时间 :
- 访问 Token 建议 1 - 2 小时
-
配合刷新 Token(有效期 7 -30 天)
POST /refresh_token Authorization: Bearer [refresh_token] -
防范重放攻击 :
- 每次请求使用唯一 Nonce 值
- 服务端维护短期 Nonce 缓存
新手避坑指南
- 前端存储风险 :
- 避免 localStorage(XSS 漏洞可能窃取 Token)
-
优先使用 HttpOnly Cookie(但要注意 CSRF 防护)
-
Token 泄露处理 :
- JWT 需要实现黑名单机制
-
短有效期 + 刷新机制降低风险
-
日志记录陷阱 :
- 永远不要记录完整 Token
- 只记录 Token 前缀用于问题排查
延伸思考
- 如何平衡安全性与用户体验?
- 频繁要求重新登录影响体验
-
过长有效期增加安全风险
-
服务端如何优雅地强制登出?
- JWT 的无状态特性导致强制失效困难
- 可以考虑维护 Token 版本号
Bearer Token 就像数字时代的钥匙——简单但需要妥善保管。掌握这些核心要点,你就能在保证安全的前提下,为用户提供流畅的认证体验。
正文完
发表至: 技术分享
五天前
