引言

Bearer Token 认证描述客户端如何向受保护资源提交访问令牌;它不定义令牌格式、登录流程、存储方式或授权策略。令牌可以是 JWT 或不透明引用,有效签名也不能替代 Scope、Tenant、Object 和业务授权。

📋 目录

关键要点

  • 什么是 Bearer Token?:Bearer Token 是一种安全令牌,授予持有者(或“承载者”)访问受保护资源的权限。它包含在 HTTP 请求的 Authorization 标头中。
  • 状态取决于部署:JWT Access Token 可以本地校验,不透明 Token 通常需要 Introspection 或服务端状态。
  • JWT 是格式而非权限:JWT 可以携带 Claims,但签名不证明调用者拥有请求中的所有对象。
  • 存储取决于场景:浏览器 Cookie、内存 Token 和移动端安全存储分别具有不同的 XSS、CSRF、生命周期和运维取舍。
  • 短期 Access Token 只是一个控制项:还需要 Refresh Token 轮换、重放检测、撤销、速率限制和事件响应。

什么是 Bearer Token 认证?

Bearer Token 认证是 RFC 6750 中定义的 HTTP 认证方案。它涉及称为 bearer tokens 的安全令牌,由认证服务器颁发。客户端应用程序在向受保护资源发出请求时,必须在 Authorization 标头中包含此令牌。

http
GET /api/resource HTTP/1.1
Host: example.com
Authorization: Bearer <token>

“Bearer”表示持有者即可提交该凭据。Resource Server 仍必须执行 Scope、Tenant、Object 和业务策略。

主要特点

  • 状态取决于部署:JWT 可以本地验证,不透明 Token 通常需要 Introspection 或服务端状态。
  • 可扩展:非常适合分布式系统和微服务架构。
  • 广泛支持:与各种协议和框架兼容,包括 OAuth 2.0 和 OpenID Connect。
  • 灵活性:可与不同的令牌格式一起使用,例如 JWT(JSON Web Tokens)和不透明令牌。

Bearer Token 的工作原理

Bearer Token 认证的工作流程通常涉及三方:

  1. 客户端:请求访问受保护资源的应用程序。
  2. 授权服务器:负责对用户进行身份验证并颁发 bearer token。
  3. 资源服务器:托管受保护资源的服务器,负责验证令牌。

认证流程

  1. 用户认证:授权服务器通过适合客户端的流程认证用户,应用不应默认收集用户密码。
  2. 令牌请求:客户端使用授权结果或客户端凭据交换 Access Token。
  3. 令牌颁发:授权服务器颁发 Bearer Token,并在适用时颁发 Refresh Token。
  4. 资源访问:客户端在向资源服务器发出的请求的 Authorization 标头中包含 bearer token。
  5. 令牌验证:Resource Server 校验算法、Issuer、Audience/Resource、Expiry、Not-before、Type、Scope,再执行对象授权。
  6. 资源响应:只有认证与具体操作策略都通过,Server 才返回资源。

代码示例

JavaScript (Node.js) 与 Passport.js

Passport.js 是 Node.js 流行的认证中间件。passport-jwt 策略简化了 bearer token 的验证。

javascript
// 配置 passport-jwt 策略
import { Strategy as JwtStrategy, ExtractJwt } from 'passport-jwt';

const options = {
  jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
  secretOrKeyProvider: loadApprovedIssuerKey,
  algorithms: ['RS256'], // 示例;应固定 Provider 允许的集合
  issuer: process.env.OIDC_ISSUER,
  audience: process.env.API_AUDIENCE
};

passport.use(new JwtStrategy(options, async (payload, done) => {
  try {
    const user = await User.findById(payload.sub);
    
    if (user) {
      return done(null, user);
    } else {
      return done(null, false);
    }
  } catch (error) {
    return done(error, false);
  }
}));

// 保护路由
app.get('/profile', passport.authenticate('jwt', { session: false }), (req, res) => {
  res.json({ user: req.user });
});

Python 与 Flask-JWT-Extended

把库作为 Resource Server 边界使用;凭据收集和 Token 颁发应由授权系统负责。

python
# Flask-JWT-Extended Resource Server 边界
import os
from flask import Flask, jsonify
from flask_jwt_extended import jwt_required, JWTManager, get_jwt_identity

app = Flask(__name__)
app.config["JWT_PUBLIC_KEY"] = os.environ["JWT_PUBLIC_KEY"]
app.config["JWT_DECODE_ISSUER"] = os.environ["OIDC_ISSUER"]
app.config["JWT_DECODE_AUDIENCE"] = os.environ["API_AUDIENCE"]
jwt = JWTManager(app)

@app.route("/profile")
@jwt_required()
def profile():
    current_user = get_jwt_identity()
    # 在此执行 Scope、Tenant、Object 和业务授权。
    return jsonify(logged_in_as=current_user), 200

Java 与 Spring Security

Spring Security 为 Java 应用程序中的 bearer token 认证提供了全面的支持。

java
@Bean
SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
    http
        .authorizeHttpRequests(auth -> auth
            .requestMatchers("/api/public").permitAll()
            .anyRequest().authenticated())
        .oauth2ResourceServer(oauth -> oauth.jwt());
    return http.build();
}

应在配置中固定 Issuer、Audience/Resource、允许算法和 JWKS 来源。认证成功不等于对象授权,服务层仍需执行 Tenant 和 Resource Policy。

安全最佳实践

  • Token 颁发和资源请求都必须使用 TLS;客户端应正确校验证书。
  • Access Token 应放在 Authorization Header 中,不要放入 Query String、URL、Referer 链接或普通日志。
  • 校验 Issuer、Audience/Resource、允许的 Algorithm、签名或 Introspection 结果、Expiry、Not-before、Token Type、Scope 和密钥轮换。
  • sub、Scope、Tenant Claim 和 Object ID 作为策略输入,而不是调用者拥有所有对象的证明。
  • 浏览器 Cookie 应结合 HttpOnly、合适的 SameSite、CSRF Token 或等价请求绑定、Origin 校验和受限 Path;HttpOnly 不能单独防止 CSRF。
  • 限制 Access Token 的生命周期和 Scope,对颁发、刷新和资源调用限速,并从 Trace 中脱敏 Token 和敏感 Claim。

Refresh Token 机制

Refresh Token 是独立凭据,不只是寿命更长的 Access Token。稳健实现应在使用时轮换、记录 Token Family、检测重放、设置总过期时间,并在登出或疑似泄露后撤销:

text
刷新请求
  -> 认证 Client 与 Refresh Token Family
  -> 拒绝过期、撤销或已使用 Token
  -> 原子标记当前 Token 已使用
  -> 颁发新的 Access Token 和 Refresh Token
  -> 检测重放时撤销整个 Family

具体存储和客户端绑定取决于 OAuth Profile 与应用类型。除非威胁模型明确要求,不要把 Refresh Token 暴露给 JavaScript。

常见问题解答 (FAQ)

1. Bearer Token 和 JWT 有什么区别? Bearer Token 是一种访问令牌。JWT (JSON Web Token) 是创建 Bearer Token 的一种流行格式。虽然大多数 Bearer Token 都是 JWT,但您也可以使用其他格式(如不透明令牌)。

2. 如何在客户端安全地存储 Bearer Token? Web 应用应根据 XSS/CSRF 威胁模型选择 Cookie Session 或其他存储设计。HttpOnly 只能限制 JavaScript 读取,不能防止 CSRF,因此还需 SameSite 和 CSRF/Origin 控制。移动应用应使用 iOS Keychain、Android Keystore 等系统安全存储。

3. 什么是刷新令牌?为什么它们很重要? Refresh Token 用于获取新的 Access Token,但寿命长本身不是安全收益。应使用轮换、重放检测、过期、安全存储和撤销,否则被盗后可能延长攻击者访问。

4. 如何撤销 Bearer Token? JWT 可能在过期前持续有效,除非 Resource Server 查询撤销状态或采用其他控制。短生命周期、高风险 Token 拒绝列表、密钥轮换和服务端会话/授权检查可以组合使用;不透明 Token 则可通过 Introspection 状态撤销。

5. 我应该使用 HS256 还是 RS256 签名 JWT? 没有一个算法对所有系统都最佳。应根据 Issuer/Resource Server 信任边界、密钥分发、库支持和轮换机制选择经过批准的对称或非对称 Profile,固定算法并拒绝 Algorithm Confusion,不能仅依据 JWT Header 做策略判断。

结论

Bearer Token 认证只是传输约定,不是完整安全架构。可部署的设计还需要明确授权流程、严格 Token 校验、操作级授权、安全存储、Refresh 轮换、撤销和可观测的失败处理。

应固定部署实际测试过的 OAuth/OIDC Profile、库版本、Issuer Metadata 和 Resource Server Policy。周边控制明确且持续验证时,Bearer Token 才能可靠地支撑 API。