跳转至

OAuth 使用双 Token 的原因

核心结论

  • Access Token 会在网络请求中频繁传输(例如放在 Authorization 头里),暴露面更大,泄露风险更高。
  • Refresh Token 通常只保存在本地安全存储中(不随每次 API 请求发送),暴露面更小,不容易泄露。

设计意义

双 Token 机制的目标是: 1. 让高频使用的凭证(Access Token)短期有效,即使泄露影响窗口也有限。 2. 让低频使用的凭证(Refresh Token)低暴露、可续期,用于换新 Access Token。

一句话理解

把“经常在路上跑的钥匙”和“家里保险箱里的总钥匙”分开,安全性会更高。

流程图(登录 / 访问 / 续签)

flowchart TD
    A[用户登录] --> B[认证服务器校验账号密码]
    B --> C[签发 Access Token + Refresh Token]
    C --> D[客户端安全存储 Token]

    D --> E[调用业务 API\n携带 Access Token]
    E --> F{Access Token 有效?}
    F -- 是 --> G[资源服务器返回数据]
    F -- 否/过期 --> H[客户端调用刷新接口\n携带 Refresh Token]

    H --> I{Refresh Token 有效?}
    I -- 是 --> J[认证服务器签发新的 Access Token\n(可选轮换 Refresh Token)]
    J --> E
    I -- 否/过期/撤销 --> K[要求用户重新登录]

时序图(更细)

sequenceDiagram
    participant U as User
    participant C as Client
    participant AS as Auth Server
    participant RS as Resource Server

    U->>C: 登录
    C->>AS: 用户凭证
    AS-->>C: Access Token + Refresh Token

    C->>RS: API 请求 + Access Token
    RS-->>C: 200 数据(Token 有效)

    C->>RS: API 请求 + 过期 Access Token
    RS-->>C: 401 Unauthorized

    C->>AS: Refresh Token 换新
    AS-->>C: 新 Access Token(可选新 Refresh Token)
    C->>RS: 重试 API + 新 Access Token
    RS-->>C: 200 数据

Refresh Token 存储建议(主流)

  • 一般将 Refresh Token 保存在 HttpOnly Cookie
  • 理由:
  • JS 读不到HttpOnly),XSS 更难直接窃取 Refresh Token。
  • 浏览器会在同站策略允许下自动携带 Cookie,刷新流程更顺滑。
  • 可实现“无感刷新”,用户体验更好。

无感刷新流程

flowchart TD
    A[请求 API] --> B{Access Token 有效?}
    B -- 是 --> C[返回数据]
    B -- 否 --> D[返回 401]
    D --> E[调用 /refresh\n浏览器自动带 refresh cookie]
    E --> F{Refresh Token 有效?}
    F -- 是 --> G[返回新 Access Token]
    G --> H[重试原请求]
    H --> I[成功]
    F -- 否 --> J[跳转登录页]

口诀(便于记忆)

  • Access Token 是“干活权限”。
  • Refresh Token 是“续命权限”。
  • 关键风控点通常发生在 refresh 过程(例如设备校验、IP/地理异常、令牌轮换与重放检测)。

React Native 存储建议

最优实践:系统安全存储(Keychain / Keystore)

  • iOS:使用 Keychain
  • Android:使用 Keystore(通常由库封装为加密后的本地存储,如加密 SharedPreferences)

RN 侧推荐: - react-native-keychain(通用、成熟) - expo-secure-store(Expo 体系更顺)