1. OAuth2.0 基础:OAuth2.0 是什么、为什么需要 OAuth2.0、OAuth2.0 的四种授权模式概述

1.1 OAuth2.0 是什么

OAuth2.0 是一个授权框架,它允许第三方应用在用户授权的前提下,获取用户在某个服务提供商(如 GitHub、、Google)上存储的受保护资源(如用户头像、邮箱、仓库列表),而无需向第三方应用暴露用户的账号密码。

OAuth2.0 的核心思想是分离“资源所有者”(用户)与“客户端应用”的凭证。客户端应用通过一个临时的、作用域受限的访问令牌(Access Token)来访问资源,而不是直接使用用户的用户名和密码。

关键角色(OAuth2.0 四元组):
  • 资源所有者(Resource Owner): 通常指用户,拥有受保护资源的访问权限。
  • 客户端(Client): 需要访问用户资源的第三方应用(如你的 Go Web 服务)。
  • 授权服务器(Authorization Server): 负责验证用户身份并颁发访问令牌的服务器。
  • 资源服务器(Resource Server): 托管受保护资源的服务器,使用访问令牌验证请求。
OAuth2.0 核心角色与交互流程 OAuth2.0 核心角色与交互流程 资源所有者 (用户) 客户端 (Go 应用) 授权服务器 (认证中心) 资源服务器 (API 服务) ① 授权请求 ② 请求令牌 ③ 颁发令牌 ④ 携带令牌访问 ⑤ 返回资源 核心原则:客户端只持有临时令牌,不持有用户密码,降低凭证泄露风险。

1.2 为什么需要 OAuth2.0

在传统的客户端-服务器认证模式中,客户端直接使用用户的用户名和密码访问资源,这种方式存在严重的安全隐患和设计缺陷:

问题 传统密码共享模式 OAuth2.0 模式
凭证泄露风险 第三方应用存储用户密码,一旦数据库泄露,用户密码完全暴露。 第三方应用只获得临时令牌,令牌可撤销、可限权,泄露后影响范围小。
权限范围控制 第三方应用获得用户账号的完全访问权限,无法精细控制。 令牌可以限定作用域(scope),如只读邮箱、只读仓库列表。
凭证回收 用户必须修改密码才能收回权限,这会影响所有使用该密码的应用。 用户只需在授权服务器上撤销特定令牌,不影响其他应用。
审计与追溯 难以区分是用户本人操作还是第三方应用操作。 每个令牌都有唯一标识,可以精确追踪到是哪个客户端在何时访问了哪些资源。
实际场景: 假设你的 Go 应用需要读取用户的 GitHub 仓库列表。使用 OAuth2.0,用户点击“使用 GitHub 登录”,GitHub 询问用户是否授权你的应用读取仓库信息。用户同意后,你的应用获得一个只读仓库的令牌,而不是用户的 GitHub 密码。即使你的应用被攻破,攻击者也只能读取仓库,无法修改或删除,也无法访问用户的私人信息。

1.3 OAuth2.0 的四种授权模式概述

OAuth2.0 定义了四种授权模式(Grant Types),以适应不同的客户端类型和安全需求。选择哪种模式取决于客户端是否能够安全地保管凭证(如 Client Secret)。

OAuth2.0 四种授权模式对比 OAuth2.0 四种授权模式对比 授权码模式 Authorization Code 隐式模式 Implicit 密码模式 Resource Owner Password 客户端凭证模式 Client Credentials ★★★★★ ★★★☆☆ ★★☆☆☆ ★☆☆☆☆ 适用场景与安全等级 后端应用 有 Server 端 可安全存储 Secret 最安全、最常用 推荐使用 纯前端应用 SPA / 移动端 无法安全存储 Secret 已不推荐使用 PKCE 替代 第一方应用 高度信任的客户端 如官方 App 需用户提供密码 谨慎使用 服务间通信 M2M 场景 无用户参与 使用 Client 身份 API 调用

1.3.1 授权码模式(Authorization Code Grant)

这是功能最完善、安全性最高的授权模式,也是本课程在 Go 项目实战中主要采用的模式。流程如下:

  1. 用户访问客户端: 用户在浏览器中访问你的 Go 应用,并点击“使用第三方登录”。
  2. 客户端重定向到授权服务器: 客户端将用户浏览器重定向到授权服务器的授权页面,并携带 client_id、redirect_uri、response_type=code 等参数。
  3. 用户授权: 用户在授权服务器上登录并确认授权。
  4. 授权服务器返回授权码: 授权服务器通过重定向将授权码(Authorization Code)发送到客户端指定的 redirect_uri。
  5. 客户端换取令牌: 客户端使用授权码,在后端向授权服务器请求访问令牌。这一步需要同时提供 client_secret 进行身份验证。
  6. 授权服务器返回令牌: 授权服务器验证授权码和客户端身份后,返回 access_token 和可选的 refresh_token。
关键安全点: 授权码必须在后端服务器之间交换,不能暴露在浏览器前端。授权码是临时的(通常几分钟内有效),且只能使用一次。这确保了即使授权码在传输过程中被截获,攻击者也无法在没有 client_secret 的情况下换取令牌。

1.3.2 隐式模式(Implicit Grant)

隐式模式是授权码模式的简化版本,专为纯前端应用(如浏览器中的 JavaScript SPA)设计。它直接返回访问令牌,跳过了授权码交换步骤。

  • 流程简化: 用户授权后,授权服务器直接在 URL 片段(Fragment)中返回 access_token。
  • 安全缺陷: 令牌直接暴露在浏览器 URL 中,容易通过浏览器历史记录、Referer 头等方式泄露。
  • 现状: OAuth2.0 安全最佳实践(BCP)已不推荐使用隐式模式,建议使用授权码模式 + PKCE(Proof Key for Code Exchange)作为替代方案。

1.3.3 密码模式(Resource Owner Password Credentials Grant)

在这种模式下,用户直接向客户端提供用户名和密码,客户端使用这些凭证向授权服务器换取令牌。

  • 适用场景: 仅适用于高度信任的客户端,如官方第一方应用或迁移场景。
  • 风险: 客户端直接接触用户密码,违背了 OAuth2.0 的核心设计原则。一旦客户端被攻破,用户密码将完全泄露。
  • 建议: 除非绝对必要,否则应避免使用此模式。本课程不推荐在 Go 项目中使用。

1.3.4 客户端凭证模式(Client Credentials Grant)

此模式用于客户端以自己的名义访问资源,而不是代表某个用户。它适用于服务器到服务器(M2M)的通信场景。

  • 无用户参与: 整个流程不涉及用户交互,客户端直接使用自己的 client_id 和 client_secret 向授权服务器请求令牌。
  • 典型场景: 你的 Go 后端服务需要调用另一个微服务的 API 来获取配置信息或执行定时任务。
  • 令牌作用域: 令牌的作用域通常限定在客户端自身的资源或权限,而不是某个用户的资源。
四种模式选择速查表:
模式 客户端类型 用户参与 安全等级 推荐度
授权码模式 有后端的应用 是 高 ★★★★★
隐式模式 纯前端应用 是 低 ★☆☆☆☆(已弃用)
密码模式 高度信任的客户端 是 中 ★★☆☆☆
客户端凭证模式 服务端应用 否 高 ★★★★☆