OAuth 2.0:它是什么,授权协议如何工作

作者: IT Sectr 发布日期: 2026-04-05 阅读时间: 10 分钟

OAuth 2.0 是一个工业级授权协议,它允许第三方应用在无需传递用户凭据的情况下,获得对用户资源的有限访问权限。该协议已成为 Web 和移动应用中委托授权的事实标准,被 Google、Facebook、Apple 和 GitHub 等平台广泛使用。根据 IETF RFC 6749 (2025),OAuth 2.0 应用于超过 85% 需要委托数据访问的 API 集成中。

要点

  • OAuth 2.0 — 委托授权协议,允许应用无需传递密码即可获取用户资源访问权限(IETF RFC 6749)
  • Access Token — 授权服务器在用户成功认证后向应用颁发的一次性访问令牌
  • Authorization Code Flow — 移动应用最安全的 Grant Type,使用 code challenge (PKCE) 防止拦截攻击
  • Refresh Token — 长期令牌,用于获取新的 Access Token,无需用户重新登录系统
  • AppAuth — IETF 推荐的库,用于在 Android 和 iOS 原生移动应用中实现 OAuth 2.0

什么是 OAuth 2.0?

OAuth 2.0 是在 IETF RFC 6749 中定义的授权协议,它允许第三方应用在不泄露用户名和密码的情况下,获得对用户资源的有限访问权限。该协议解决了密码模型的根本问题:您信任密码的应用将获得对帐户所有数据的无限访问权限。OAuth 2.0 通过颁发具有明确限制访问范围(scope)的临时令牌来取代这种方法。

OAuth 2.0 的架构是委托授权。用户(Resource Owner)授权应用(Client)访问存储在资源服务器(Resource Server)上的数据,通过一个中介——授权服务器(Authorization Server)。授权服务器颁发 Access Token——一个加密字符串,由应用提交给资源服务器以访问数据。OAuth 2.0 与 SAML 和 OpenID Connect 的重要区别在于:OAuth 2.0 解决的是授权问题(允许做什么),而不是身份验证问题(用户是谁)。OpenID Connect (OIDC) 协议建立在 OAuth 2.0 之上,用于身份验证。

该协议受到所有主要平台的支持。Google 使用 OAuth 2.0 访问 Google APIs(Gmail、Drive、Calendar),Facebook 用于 Graph API,Apple 用于 Sign in with Apple(ASAuthorizationAppleIDProvider),GitHub 用于访问仓库。在移动开发环境中,OAuth 2.0 是集成第三方服务的标准机制:通过社交网络登录、访问云存储、以用户身份发布内容。

OAuth 2.0 的角色和组件

OAuth 2.0 协议定义了四个角色,它们的交互构成了完整的授权周期。理解每个角色对于在移动应用中正确实现协议至关重要。

协议的四个角色

角色描述示例
Resource Owner数据所有者——允许访问其资源的用户点击「通过 Google 登录」的应用用户
Client代表所有者请求访问资源的应用需要访问 Google Drive 的移动应用
Authorization Server在认证和授权后颁发令牌的服务器accounts.google.com — Google 授权服务器
Resource Server通过令牌提供对受保护资源访问的 APIwww.googleapis.com — Google Drive API 资源服务器

协议的核心实体包括 Access TokenRefresh TokenAuthorization Code。Access Token 是短期令牌(通常 15–60 分钟),在每次数据请求时提交给资源服务器。Refresh Token 是长期令牌(数天或数周),用于获取新的 Access Token 而无需用户重新登录。Authorization Code 是用户授权后颁发的临时代码,用于交换 Access Token 和 Refresh Token。

Grant Types:授权场景

OAuth 2.0 定义了多种 Grant Types——获取令牌的场景,每种都针对特定的客户端类型和安全上下文。选择正确的 Grant Type 是在移动应用中设计授权时的关键架构决策。

主要的 Grant Types:Authorization Code(对于具有服务器组件的移动和 Web 应用最安全)、带 PKCE 的 Authorization Code(Proof Key for Code Exchange——用于无后端的移动和 SPA 应用)、Client Credentials(用于无需用户参与的服务器到服务器认证)、Resource Owner Password Credentials(已废弃——直接传递密码)。根据 OAuth Security BCP (RFC 9700) 的建议,PKCE 是公共客户端(移动应用、SPA)的强制扩展。

主要的 Grant Types

  • Authorization Code + PKCE — 适用于原生移动应用的推荐 Grant Type。客户端生成加密 code_verifier,计算 code_challenge(SHA-256 哈希),服务器在交换代码换取令牌时验证其一致性。这防止了应用与服务器之间的 authorization code 拦截
  • Client Credentials — 用于机器对机器授权,其中客户端是已知且已认证的。应用使用其 client_id 和 client_secret 获取令牌。不需要用户参与。典型场景:服务器应用调用 API 进行批量数据处理
  • Device Authorization Grant — 适用于无浏览器的设备(智能电视、物联网)。用户在另一台设备上点击链接并输入代码。例如,在电视上通过智能手机授权 Netflix 时使用
  • Resource Owner Password Credentials — 已废弃的 Grant Type,被 OAuth Security BCP 禁止。密码直接传递给客户端,违反了零知识认证原则。仅用于从旧系统迁移

移动应用的 Authorization Code Flow 与 PKCE

带 PKCE 的 Authorization Code Flow 是适用于原生移动应用的推荐 OAuth 2.0 配置。PKCE (Proof Key for Code Exchange) 添加了额外的保护层,防止 authorization code 拦截攻击。该协议在 IETF RFC 7636 中有描述。

PKCE 的逐步流程

步骤顺序:(1) 客户端生成随机的 code_verifier(43–128 个字符的字符串,仅限 unreserved characters),(2) 客户端计算 code_challenge = SHA-256(code_verifier),(3) 客户端在浏览器中打开授权服务器上的用户授权页面,传递 code_challenge,(4) 授权成功后,服务器通过自定义 URI scheme(应用深度链接)将 authorization code 返回给应用,(5) 客户端向服务器发送 authorization code + code_verifier,(6) 服务器验证 SHA-256(code_verifier) === code_challenge 并颁发 Access Token + Refresh Token。

PKCE 的优势在于——即使攻击者在 URI scheme 中拦截了 authorization code,也无法在没有 code_verifier 的情况下将其交换为令牌,因为 code_verifier 只有合法客户端才知道。在移动应用中,应使用 Chrome Custom Tabs(Android)或 ASWebAuthenticationSession(iOS)打开浏览器——这可以确保系统浏览器无法从应用内存中访问 code_verifier。

通过 AppAuth 在 Android 上实现 OAuth 2.0

AppAuth 是 IETF 推荐的用于原生应用的 OAuth 2.0 和 OpenID Connect 参考实现。该库支持 PKCE、Chrome Custom Tabs、用于返回 authorization code 的自定义 URI scheme 以及自动令牌刷新。适用于 Android 的 AppAuth 可通过 `net.openid:appauth:0.11.1` 依赖项获取。

kotlin
val serviceConfig = AuthorizationServiceConfiguration.fromUrl(
    Uri.parse("https://accounts.google.com/.well-known/openid-configuration")
)

val request = AuthorizationRequest.Builder(
    serviceConfig,
    "CLIENT_ID.apps.googleusercontent.com",
    ResponseTypeValues.CODE,
    Uri.parse("com.example.app:/oauth2callback")
)
.setScope("openid profile email")
.setCodeVerifier(
    CodeVerifierUtil.generateRandomCodeVerifier()
)
.build()

val authService = AuthorizationService(context)
val intent = authService.getAuthorizationRequestIntent(request)

// 启动 Chrome Custom Tab 进行授权
startActivityForResult(intent, REQUEST_CODE_AUTH)

获取 authorization code (onActivityResult) 后,应用通过 TokenRequest 将其交换为 Access Token 和 Refresh Token。令牌通过 EncryptedSharedPreferences (Android Security Crypto) 加密保存在 SharedPreferences 中。Refresh Token 必须存储在 KeyStore 中——这是一个硬件密钥存储,其他应用无法读取。每次 Access Token 过期时,应用使用 Refresh Token 获取新的令牌——用户无需重新授权。

kotlin
// 交换 authorization code 获取令牌
val data = intent?.data ?: return
val resp = AuthorizationResponse.fromIntent(data)
val exchangeReq = resp?.createTokenExchangeRequest()
    ?: return

authService.performTokenRequest(
    exchangeReq,
    ClientAuthentication.none()
) { tokenResp, ex ->
    if (tokenResp != null) {
        // 已获取 Access Token 和 Refresh Token
        val accessToken = tokenResp.accessToken
        val refreshToken = tokenResp.refreshToken
        // 保存到 EncryptedSharedPreferences
        saveTokens(accessToken, refreshToken)
    }
}

以上代码展示了带 PKCE 的完整 OAuth 2.0 循环:通过 OpenID Connect Discovery 创建服务器配置、生成带 code_verifier 的授权请求、启动 Chrome Custom Tab、通过自定义 URI scheme 接收 authorization code 以及通过 Token Request 交换代码获取令牌。处理 Access Token 过期非常重要:当资源服务器返回 HTTP 401 响应时,应用应使用 Refresh Token 获取新的 Access Token 并重新执行请求。

OAuth 2.0 安全性:常见攻击与防护

OAuth 2.0 是一个复杂的协议,具有多个攻击点。IETF Security BCP (RFC 9700) 描述了超过 20 种 OAuth 2.0 漏洞类别。对于移动应用,最关键的包括:通过自定义 URI scheme 拦截 authorization code、对回调端点的 CSRF 攻击、从不安全存储中窃取 Refresh Token 以及通过意图拦截进行客户端篡改。

针对这些攻击的防护包括强制措施:(1) 使用 S256 code_challenge 的 PKCE——即使在 URI scheme 拦截的情况下也能防止 authorization code 拦截;(2) 使用 nonce 或 state 参数防止 CSRF——服务器验证 authorization code 与原始请求匹配;(3) 仅在 KeyStore(Android)或 Keychain(iOS)中存储 Refresh Token——不在 SharedPreferences 或 UserDefaults 中;(4) 使用带 Certificate Pinning 的 TLS 以防止传输层的中间人攻击;(5) 验证 redirect_uri——授权服务器必须严格验证与注册 URI 的匹配。

IETF 的其他建议:移动应用应使用通过安全审计的 AppAuth 或类似库;不要依赖 WebView 进行 OAuth(WebView 无法将数据与主应用隔离);实现自动 Refresh Token 轮换(一个 Refresh Token 只能使用一次);通过 Android 的 TrustManager 和 iOS 的 URLSession 添加 Certificate Pinning。OpenID Connect Discovery (well-known endpoint) 有助于自动确定授权服务器的正确端点,并避免重定向到钓鱼页面。

常见问题

OAuth 2.0 和 OpenID Connect 有什么区别?

OAuth 2.0 是授权协议(允许做什么?),而 OpenID Connect (OIDC) 是身份验证协议(用户是谁?)。OIDC 建立在 OAuth 2.0 之上,并添加了 ID Token——包含用户身份信息的 JWT 令牌。OAuth 2.0 提供 Access Token,OIDC 在此基础上增加了 ID Token 和 UserInfo 端点以获取用户资料。

什么是 Bearer Token,它有什么危险?

Bearer Token 是在 HTTP 头 Authorization: Bearer 中出示的 Access Token。它的危险在于,任何拥有该令牌的人都可以访问资源——令牌未绑定到客户端。因此,Bearer Token 必须仅通过 TLS (HTTPS) 传输,具有短暂的生命周期(15–60 分钟),并且绝不能存储在日志或 URL 参数中。

为什么 PKCE 对移动应用是强制性的?

移动应用是公共客户端,没有 client_secret(秘密无法在 APK/IPA 中保护)。没有 PKCE 时,攻击者可以通过自定义 URI scheme(例如 malformed://callback?code=ABC)拦截 authorization code 并将其交换为令牌。PKCE 添加了仅应用知道的 code_verifier,使被拦截的代码无效。

Access Token 应该多久更新一次?

典型的 Access Token 持续 15–60 分钟(由授权服务器配置)。每次向资源服务器发出 HTTP 请求时,都会检查响应:如果状态码为 401,应用调用 Refresh Token Flow 获取新的 Access Token。Refresh Token 持续 24 小时到几个月不等,具体取决于提供商的安全策略。更换 Refresh Token 时,旧的将被作废。

可以使用 WebView 进行 OAuth 2.0 吗?

不可以——IETF Security BCP (RFC 9700) 禁止在移动应用中使用 WebView 进行 OAuth 2.0。WebView 不会将 cookie 和数据与主应用隔离,这使应用能够拦截用户的凭据。应使用 Chrome Custom Tabs(Android)或 ASWebAuthenticationSession(iOS)代替 WebView——它们是与应用隔离的系统浏览器组件。

总结

  • OAuth 2.0 — 委托授权协议 (IETF RFC 6749),用具有有限访问范围的临时令牌代替密码传递
  • Authorization Code + PKCE — 移动应用的强制 Grant Type,防止通过 URI scheme 拦截 authorization code
  • Access Token — 短期令牌 (15–60 分钟),在每次数据请求时出示给资源服务器
  • Refresh Token — 长期令牌,用于无缝更新 Access Token,无需用户重新登录
  • AppAuth — Android 和 iOS 的 OAuth 2.0 参考库,支持 PKCE、Custom Tabs 和 KeyStore
  • WebView 被禁止 — 根据 IETF RFC 9700,OAuth 2.0 必须通过系统浏览器(Custom Tabs / ASWebAuthenticationSession)执行
  • OpenID Connect — 基于 OAuth 2.0 的身份验证协议,添加 ID Token (JWT) 用于用户身份识别

我们将开发一款交钥匙移动应用程序

IT Sectr自2017年以来为初创企业和企业打造iOS和Android应用程序。我们将为您提供咨询并提出最佳解决方案。

讨论项目

另请阅读