@freeCodeCamp: OAuth 2.0 是一个框架,允许应用在不共享凭证的情况下有限地访问你的数据。但流程一开始可能会让人困惑……
摘要
一份全面的指南,从头讲解 OAuth 2.0 概念,涵盖授权码流程、令牌、PKCE 等,适合后端开发者。
查看缓存全文
缓存时间: 2026/07/31 00:46
OAuth 2.0 是一个框架,允许应用在不共享凭证的情况下有限访问你的数据。
但它的流程一开始可能会让人困惑。
这里,@ashutoshkrris 从头讲解 OAuth 2.0,涵盖客户端、令牌、授权类型和安全认证流程等内容。
https://freecodecamp.org/news/oauth-2-0-guide-for-backend-developers/…
OAuth 2.0 如何工作:后端开发者实用指南
来源:https://www.freecodecamp.org/news/oauth-2-0-guide-for-backend-developers/ OAuth 2.0 如何工作:后端开发者实用指南如果你问十位初级开发者 OAuth 2.0 是如何工作的,九位会开始背诵术语,比如“授权服务器”、“Bearer 令牌”、“PKCE”和“隐式授权”。他们可能还会画一个六条箭头来回交叉的序列图。
但如果你问他们某个特定的 HTTP 请求为什么存在,或者去掉它会出什么问题,他们往往无法给出很好的解释。
在我看来,这是因为 OAuth 通常是以反向的方式教授的。大多数教程从定义和序列图开始,而没有先解释协议最初为什么要这样设计。
在本指南中,我们将改变这一点。我们将从实际问题出发,逐步构建 OAuth 2.0 的概念,自然地得出协议解决方案。等我们在 Spring Boot 中编写代码时,每个参数、重定向和令牌都会变得完全合理。
我们将涵盖以下内容:
- OAuth 之前的问题 (https://www.freecodecamp.org/news/oauth-2-0-guide-for-backend-developers/#heading-the-problem-before-oauth)
- OAuth 2.0 到底是什么(以及不是什么) (https://www.freecodecamp.org/news/oauth-2-0-guide-for-backend-developers/#heading-what-oauth-20-actually-is-and-isnt)
- 应用注册:凭证从何而来 (https://www.freecodecamp.org/news/oauth-2-0-guide-for-backend-developers/#heading-application-registration-where-credentials-come-from)
- OAuth 2.0 中的四个角色 (https://www.freecodecamp.org/news/oauth-2-0-guide-for-backend-developers/#heading-the-four-roles-in-oauth-20)
- 访问令牌和作用域 (https://www.freecodecamp.org/news/oauth-2-0-guide-for-backend-developers/#heading-access-tokens-and-scopes)
- 授权码流程 (https://www.freecodecamp.org/news/oauth-2-0-guide-for-backend-developers/#heading-the-authorization-code-flow)
- 为什么需要两步重定向 (https://www.freecodecamp.org/news/oauth-2-0-guide-for-backend-developers/#heading-why-the-two-step-redirect-exists)
- 令牌过期与刷新令牌 (https://www.freecodecamp.org/news/oauth-2-0-guide-for-backend-developers/#heading-token-expiration-and-refresh-tokens)
- PKCE:保护公共客户端 (https://www.freecodecamp.org/news/oauth-2-0-guide-for-backend-developers/#heading-pkce-protecting-public-clients)
- state 与 PKCE:阻止不同的攻击 (https://www.freecodecamp.org/news/oauth-2-0-guide-for-backend-developers/#heading-state-vs-pkce-stopping-different-attacks)
- OAuth 2.0 与 OpenID Connect (OIDC) 及 JWT (https://www.freecodecamp.org/news/oauth-2-0-guide-for-backend-developers/#heading-oauth-20-vs-openid-connect-oidc-amp-jwts)
- OAuth 2.1 是什么? (https://www.freecodecamp.org/news/oauth-2-0-guide-for-backend-developers/#heading-what-is-oauth-21)
- 生产环境中应避免的安全陷阱 (https://www.freecodecamp.org/news/oauth-2-0-guide-for-backend-developers/#heading-production-security-pitfalls-to-avoid)
- 最后想法 (https://www.freecodecamp.org/news/oauth-2-0-guide-for-backend-developers/#heading-final-thoughts)
OAuth 之前的问题
假设我们正在构建 TravelBuddy,一个帮助用户规划行程的 Spring Boot 应用。
TravelBuddy 有一个功能,可以自动检测日程冲突,并将行程安排直接插入用户的 Google 日历。
为此,TravelBuddy 需要访问 Google Calendar API。具体来说,它需要代表用户 Alice 读取现有事件并写入新事件。
在 OAuth 出现之前,2005 年我们该如何解决这个问题?
密码共享反模式
如果没有像 OAuth 这样的协议,TravelBuddy 就需要向 Alice 索要她的 Google 用户名和密码。
一个线性流程图展示 Alice 将她的完整账户凭证直接发送给 TravelBuddy,然后 TravelBuddy 将这些凭证转发给 Google Calendar API。这种模式迫使用户将账户的完全控制权交给第三方应用。Alice 会在 TravelBuddy 的界面上输入她的 Google 密码。TravelBuddy 会将她的密码存储在数据库中,并在需要获取或创建日历事件时使用这些凭证登录 Google。
这种方法可行,但会带来严重的安全和运营问题:
- 权限过大: TravelBuddy 只需要管理日历事件。但由于它持有 Alice 的实际 Google 密码,它还可以读取她的 Gmail、查看 Google Drive 文件、删除照片或更改账户密码。没有办法给 TravelBuddy 有限 的访问权限。
- 无法细粒度撤销: 如果 Alice 想停止 TravelBuddy 访问她的日历,她唯一的选择是更改 Google 密码。这样做会破坏她之前授权的所有其他应用。
- TravelBuddy 的存储责任: TravelBuddy 现在存储着数千个 Google 账户的明文或可解密密码。TravelBuddy 侧的一次 SQL 注入或数据库泄露就会危及用户在 Google 上的整个数字生活的万能钥匙。
- 钓鱼行为常态化: 训练用户在第三方应用中输入其主要 Google 凭证会让他们养成糟糕的安全习惯。
我们需要一种方式,让 Alice 授予 TravelBuddy 在 Google 日历上执行特定操作的权限,而绝不将她的 Google 密码交给 TravelBuddy。
这种能力被称为 委托授权,而这正是 OAuth 2.0 所提供的。
OAuth 2.0 到底是什么(以及不是什么)
OAuth 2.0 是一个用于 委托授权 的开放标准。
它提供了一个框架,允许用户授予第三方应用在另一服务上对其资源的有限访问权限,而无需共享其凭证。
在继续之前,我们必须解决 Web 开发中最常见的一个误解。
身份验证 vs. 授权
开发者经常互换使用这两个术语,但它们回答的是两个根本不同的问题:
- 身份验证 (AuthN): 你是谁?(身份)
- 授权 (AuthZ): 你有权做什么?(权限)
一个流程图说明身份验证在授权之前。第一个框建立身份(“你是 Alice”),然后输入第二个框建立权限(“Alice 可以读取/写入事件,但不能删除日历”)。OAuth 2.0 严格来说是一个授权框架。它不指定如何验证用户身份、如何颁发身份详细信息或如何存储用户账户。它只关心发放权限密钥(令牌),以便一个服务可以代表用户与另一个服务通信。
当你点击网站上的“使用 Google 登录”时,该交互使用的是建立在 OAuth 之上的一个扩展,称为 OpenID Connect (OIDC),我们将在后文介绍。但核心的 OAuth 2.0 完全关于授权。
应用注册:凭证从何而来
在 TravelBuddy 启动 OAuth 流程之前,我们必须先在 Google Cloud Console 中注册 TravelBuddy。
注册过程中,Google 会提示 TravelBuddy 提供两个关键信息:
- 应用名称和 Logo: 在用户同意页面上显示。
- 重定向 URI: Google 允许发送授权码的确切回调 URL(例如
https://travelbuddy.com/login/oauth2/code/google)。
注册完成后,Google 会向 TravelBuddy 颁发两个凭证:
client_id:一个公共标识符(如用户名),用于标识 TravelBuddy。 可以安全地嵌入公共链接或前端代码中。client_secret:一个机密密钥(如密码), 由 TravelBuddy 的后端服务器在将授权码交换为令牌时用于向 Google 验证自身身份。
OAuth 2.0 中的四个角色
OAuth 2.0 定义了四个角色。让我们直接将它们映射到我们的 TravelBuddy 示例中,这样这些术语就不再是抽象定义了。
一个图表将四个实体连接起来:Alice(资源所有者)向 TravelBuddy(客户端)授予权限。Alice 在 Google 的授权服务器上进行身份验证,该服务器向 TravelBuddy 颁发令牌。TravelBuddy 使用该令牌向 Google Calendar(资源服务器)请求数据,资源服务器再向授权服务器验证令牌。- 资源所有者: 拥有数据的用户。在我们的示例中,这是 Alice。她拥有自己的 Google 日历。
- 客户端: 试图访问用户数据的第三方应用。在我们的示例中,这是 TravelBuddy(我们的 Spring Boot 后端)。之所以称为“客户端”,是因为它作为 API 的客户端运行。
- 授权服务器: 对用户进行身份验证、获取用户同意并颁发访问令牌的服务器。在我们的示例中,这是 Google 的 OAuth 服务器(
accounts.google.com)。 - 资源服务器: 托管受保护用户数据的服务器。在我们的示例中,这是 Google Calendar API(
www.googleapis.com/calendar)。
注意 Google 的职责被分成两个独立的角色:授权服务器(颁发令牌)和资源服务器(托管 API)。在大型组织中,这些通常是不同团队维护的不同服务。
访问令牌和作用域
TravelBuddy 没有拿到 Alice 的密码,而是批准颁发了 访问令牌。
访问令牌是一串字符,类似于临时的钥匙卡。当 TravelBuddy 向 Google Calendar 发出 HTTP 请求时,它会在请求头中出示这个令牌。
访问令牌有三个密码所没有的关键属性:
- 有限的作用域: 只能用于特定的权限。
- 有限的生命周期: 会在短时间后自动过期(通常为几分钟或几小时)。
- 可撤销: Alice 或 Google 可以随时撤销令牌,而不会影响 Alice 的账户密码。
什么是作用域?
作用域是一个字符串,定义了所请求的确切权限。TravelBuddy 不会要求“Google 账户访问权限”,而是请求特定的作用域。
当 TravelBuddy 将 Alice 重定向到 Google 时,它会指定所请求的作用域:
- 读取日历事件:
https://www.googleapis.com/auth/calendar.events.readonly - 创建/编辑日历事件:
https://www.googleapis.com/auth/calendar.events
当 TravelBuddy 将 Alice 重定向到 Google 时,它会指定所请求的作用域。Google 会向 Alice 显示这些确切的权限:
“TravelBuddy 希望获得查看和编辑您的 Google 日历事件的权限。”
如果 Alice 同意,Google 颁发的访问令牌将严格绑定到这些请求的作用域。如果 TravelBuddy 尝试使用相同的令牌读取 Alice 的电子邮件,Google 的资源服务器将拒绝请求,并返回 403 Forbidden 状态码。
授权码流程
现在我们已经了解了角色和令牌,TravelBuddy 究竟如何获取访问令牌?
对于服务器端应用(如我们的 Spring Boot 应用),标准且最安全的流程是 授权码流程。
以下是事件序列。我们将在图表之后立即详细讲解每一步。
一个九步序列图详细说明授权过程。用户发起同步,被重定向到 Google 进行登录和同意,并通过浏览器重定向收到一个临时的授权码。TravelBuddy 的后端直接与 Google 交换该代码和它的 Client Secret 以获得访问令牌,然后使用 Bearer 令牌调用 Calendar API。让我们逐步分解。
步骤 1:用户发起操作
Alice 正在使用 TravelBuddy 的界面,点击“连接 Google 日历”。
步骤 2:TravelBuddy 构造重定向 URL
TravelBuddy 的后端不提示输入凭证。相反,它生成一个指向 Google 授权服务器的 URL,并指示 Alice 的浏览器重定向到那里。
该 URL 看起来像这样:
GET https://accounts.google.com/o/oauth2/v2/auth?response_type=code&client_id=TRAVELBUDDY_CLIENT_ID&redirect_uri=https://travelbuddy.com/login/oauth2/code/google&scope=https://www.googleapis.com/auth/calendar.events&state=xyz123
我们来分析每个参数的作用:
response_type=code:告诉 Google 我们正在使用授权码流程。client_id:TravelBuddy 在开发者应用注册时获得的一个公共标识符。redirect_uri:用户在完成同意后,Google 应将 Alice 送回的那个 URL。scope:TravelBuddy 请求的权限。state:TravelBuddy 生成的随机字符串,用于防止跨站请求伪造(CSRF)攻击。
步骤 3:Alice 进行身份验证并同意
Alice 的浏览器进入 Google 的域名(accounts.google.com)。
Google 会验证 Alice 是否已登录。如果没有,Google 会要求她登录。TravelBuddy 从未看到此交互。
身份验证成功后,Google 会显示同意屏幕,列出 TravelBuddy 的名称和请求的作用域。
步骤 4 和 5:Google 颁发授权码
Alice 点击“批准”。Google 的授权服务器将 Alice 的浏览器重定向回 TravelBuddy 注册的 redirect_uri,并在查询字符串中附加一个短期的 授权码 和 state 参数:
GET https://travelbuddy.com/login/oauth2/code/google?code=4/0AX4XfWh...&state=xyz123
TravelBuddy 的后端验证返回的 state 是否与最初发送的一致。如果一致,TravelBuddy 就获取 code。
步骤 6 和 7:TravelBuddy 将代码交换为令牌
现在 TravelBuddy 的 后端服务器 向 Google 的令牌端点(https://oauth2.googleapis.com/token)发出直接的服务器到服务器 POST 请求:
`` POST /token HTTP/1.1 Host: oauth2.googleapis.com Content-Type: application/x-www-form-urlencoded
grant_type=authorization_code& code=4/0AX4XfWh…& redirect_uri=https://travelbuddy.com/login/oauth2/code/google& client_id=TRAVELBUDDY_CLIENT_ID& client_secret=TRAVELBUDDY_CLIENT_SECRET ``
Google 验证授权码和 TravelBuddy 的 client_secret。如果有效,Google 会回复一个包含访问令牌的 JSON 负载:
{ "access_token": "ya29.a0ARrdaM...", "token_type": "Bearer", "expires_in": 3600, "refresh_token": "1//04rG...", "scope": "https://www.googleapis.com/auth/calendar.events" }
步骤 8 和 9:调用 API
TravelBuddy 现在安全地存储此访问令牌,并使用它代表 Alice 调用 Google Calendar API:
GET /calendar/v3/users/me/calendarList HTTP/1.1 Host: www.googleapis.com Authorization: Bearer ya29.a0ARrdaM...
Google Calendar 收到请求,提取 Bearer 令牌,与 Google 的认证基础设施核对以验证其有效性和作用域是否正确,然后返回 Alice 的日历数据。
为什么需要两步重定向
到了这里,初级开发者几乎总会问一个很好的问题:
“为什么要有步骤 4 和步骤 6?为什么 Google 不在步骤 4 中直接将访问令牌返回到浏览器中?”
为什么要把一个临时的 authorization_code 返回给浏览器,然后立即再做一个后端调用来把它换成实际的 access_token?
答案归结为 前端通道 vs. 后端通道 的安全性。
- 前端通道(浏览器): 浏览器是一个不受信任、高度暴露的环境。重定向 URI 会经过浏览器历史记录、系统日志、referer 头以及浏览器扩展。如果 Google 直接在浏览器的 URL
相似文章
@0x0SojalSec: 开源 OAuth 2.0 认证服务器,可自行托管。构建你自己的认证服务,一个自托管的 OAuth 2.0…
一个开源 OAuth 2.0 认证服务器,可自行托管,支持 Google、GitHub、邮箱登录、自定义提供商以及现代部署平台。推荐后端工程师学习现代认证系统的工作原理。
Cloudflare 为所有用户推出了自管理 OAuth
Cloudflare 为所有客户推出了自管理 OAuth,允许开发者创建和管理 OAuth 客户端以实现委托 API 访问,从而提升 Cloudflare 应用生态的安全性和可扩展性。
@freeCodeCamp:在处理云基础设施时,安全性应始终放在首位。在此指南中,@ijaydimples 覆盖了……
本指南涵盖初学者需要了解的 AWS 云安全关键概念,包括根用户与 IAM 用户、共享责任模型和用户权限。
CLI 认证的正确方式
本文批评了许多 CLI 工具常用的 OAuth 回环认证模式,该模式在无头机器上无法工作,并提倡使用自 2019 年起已成为标准的设备码流等替代方法。
我构建了一个本地 OAuth/API 中心,让自主智能体能够运行真实工作流
一位开发者构建了一个本地 OAuth/API 中心,旨在简化将自主编码智能体连接到 YouTube 和 Google Search Console 等真实服务的过程,并提供了用于频道分析和编辑规划的初始工作流。