大家好,我是程序员柏风,AI 最全的 Vibecoding 学习地图 http://coderoadmap.cn 作者。
令牌认证
Bearer Token 表示:谁持有这个串,谁就享有对应权限——常见于 JWT、opaque token、API Key。Spring REST API 多走 Authorization: Bearer <token>,与 Cookie 会话 并列,是前后端分离的主路径。本课建立 JWT 直觉与坑,完整授权码流见 oauth-essentials。
学习目标
- 区分 opaque token 与 JWT 的校验方式
- 列出 JWT 必须控制的 exp、iss、aud、alg 等要点
- 对接 sb-jwt 与 oauth-resource
Bearer 头格式
GET /api/me HTTP/1.1
Authorization: Bearer eyJhbGciOiJIUzI1NiIs...
服务器 不解析 Cookie,从 Header 取 token 校验。CORS 预检需允许 Authorization(sec-cors)。
Opaque vs JWT
| Opaque | JWT | |
|---|---|---|
| 内容 | 随机 ID,服务端查 session/DB | 自包含 JSON + 签名 |
| 撤销 | 删 session 即失效 | 短 exp + 黑名单 / refresh 轮换 |
| 扩展 | 服务端存权限 | claims 里放 role(注意体积) |
| 校验 | 查存储 | 验签 + 验 exp/iss |
本站 backend 若用 Sa-Token / 自签 JWT,思路与 Spring Security OAuth2 Resource Server 类似:验签密钥保密、过期要短。
JWT 结构(直觉)
header.payload.signature
Payload 示例 claims:
{
"sub": "user-42",
"exp": 1735689600,
"iss": "https://auth.example.com",
"aud": "api.example.com",
"scope": "read:orders"
}
不要在 JWT 里放:密码、信用卡、过大 PII——payload 仅 Base64Url,无加密(除非 JWE,少用)。
安全要点
- 算法:禁止接受
alg: none;RS256 / ES256 优于共享密钥 HS256 泄露一发全灭(视架构而定) - 密钥:
JWT_SECRET放环境变量,长度足够,可轮换(双 key 过渡期) - 过期:access token 分钟级;长期用 refresh token 单独保护
- 传输:仅 HTTPS(sec-ssl)
- 存储(前端):优先 内存;localStorage 有 XSS 窃取风险——配合 sec-csp
- 权限:JWT 里
role只是 hint,服务端仍要查库或版本号 防越权(sec-owasp A01)
Spring Resource Server 片段
spring:
security:
oauth2:
resourceserver:
jwt:
issuer-uri: https://auth.example.com
@GetMapping("/api/me")
@PreAuthorize("hasAuthority('SCOPE_read:profile')")
public Profile me(@AuthenticationPrincipal Jwt jwt) {
return profileService.load(jwt.getSubject());
}
与 oauth-resource 同一模型:认证(Jwt)+ 授权(Scope / Role) 分开。
OAuth 与「自建 JWT 登录」分工
| 场景 | 倾向 |
|---|---|
| 第一方 SPA/移动端用户名密码 | 登录接口签 JWT + refresh(sb-jwt) |
| 第三方「用 GitHub 登录」 | oauth-flows + OIDC |
| 微服务间 | 客户端凭证或 mTLS,短 JWT |
oauth-vs-jwt 专门对比本站形态,避免 把 OAuth 当登录密码传输 误用。
API Key
简单场景:X-API-Key: ... 或 query(不推荐 query,易进日志)。应 可撤销、可 scoped、可限流,权限小于用户 JWT。
练习
- 在 jwt.io 解码示例 token(勿粘贴生产 token),指出 exp 与 sub
- 列出:JWT 被盗后你能做的三条响应措施
- 阅读 oauth-oidc,说明 id_token 与 access_token 区别
小结
Bearer = 持票入场;JWT 要短过期、验签、少敏感 claims。 下一课 Cookie 会话与 HttpOnly / SameSite。