适用于移动应用和桌面应用的 OAuth 2.0

图片说明:概览概述了 Google 支持的 OAuth 2.0 流程,可帮助您确保为应用选择合适的流程。

本文档介绍了在手机、平板电脑和计算机等设备上安装的应用如何使用 Google 的 OAuth 2.0 端点对 Google API 的访问权限进行授权。

OAuth 2.0 可让用户与应用共享特定数据,同时保持其用户名、密码和其他信息的私密性。例如,应用可以使用 OAuth 2.0 向用户授予权限,以便将文件存储在他们的 Google 云端硬盘中。

已安装的应用会分发到各个设备,并且假定这些应用不能保密。当用户访问应用或在应用运行时,用户可以访问 Google API。

此授权流程类似于网络服务器应用。两者的主要区别在于,已安装的应用必须打开系统浏览器并提供本地重定向 URI,以便处理来自 Google 授权服务器的响应。

替代方案

对于移动应用,您可能希望在 AndroidiOS 设备上使用 Google 登录功能。Google 登录客户端库会处理身份验证和用户授权,而且可能比此处所述的较低级别协议更简单。

对于在不支持系统浏览器或输入功能有限的设备(例如电视、游戏机、相机或打印机)上运行的应用,请参阅适用于电视和设备的 OAuth 2.0在电视和受限输入设备上登录

库和示例

我们建议您借助以下库和示例来实现本文档中所述的 OAuth 2.0 流程:

前提条件

为您的项目启用 API

任何调用 Google API 的应用都需要在 API Console中启用这些 API。

如需为您的项目启用该 API,请按以下步骤操作:

  1. Open the API Library (在 Google API Console中)。
  2. If prompted, select a project, or create a new one.
  3. API Library 列出了所有可用的 API(按产品系列和热门程度分组)。如果您要启用的 API 在列表中不可见,请使用搜索功能查找该 API,或点击该 API 所属产品系列中的查看全部
  4. 选择您要启用的 API,然后点击启用按钮。
  5. If prompted, enable billing.
  6. If prompted, read and accept the API's Terms of Service.

创建授权凭据

任何使用 OAuth 2.0 访问 Google API 的应用都必须使用授权凭据向 Google 的 OAuth 2.0 服务器标识相应应用。以下步骤说明了如何为项目创建凭据。然后,您的应用可以使用这些凭据访问您为该项目启用的 API。

  1. Go to the Credentials page.
  2. 依次点击创建凭据 > OAuth 客户端 ID
  3. 以下部分将介绍 Google 的授权服务器支持的客户端类型和重定向方法。选择为应用推荐的客户端类型,为您的 OAuth 客户端命名,并根据情况设置表单中的其他字段。

自定义 URI 方案(Android、iOS、UWP)

建议对 Android 应用、iOS 应用和 Universal Windows Platform (UWP) 应用使用自定义 URI 方案。

Android
  1. 选择 Android 应用类型。
  2. 输入 OAuth 客户端的名称。此名称会显示在项目的 Credentials page 中,以标识客户端。
  3. 输入 Android 应用的软件包名称。此值在应用配置文件的 <manifest> 元素的 package 属性定义中定义。
  4. 输入应用分发的 SHA-1 签名证书指纹。
    • 如果您的应用使用 Google Play 应用签名,请从 Play 管理中心的“应用签名”页面复制 SHA-1 指纹。
    • 如果您管理自己的密钥库和签名密钥,请使用 Java 附带的 keytool 实用程序以直观易懂的格式输出证书信息。复制 keytool 输出的 Certificate fingerprints 部分中的 SHA1 值。如需了解详情,请参阅 Google API for Android 文档中的对客户端进行身份验证
  5. 点击创建
iOS
  1. 选择 iOS 应用类型。
  2. 输入 OAuth 客户端的名称。此名称会显示在项目的 Credentials page 中,以标识客户端。
  3. 输入应用的软件包标识符。软件包 ID 是应用信息属性列表资源文件 (info.plist) 中 CFBundleIdentifier 键的值。该值最常显示在 Xcode 项目编辑器的“General”窗格或“Signing &Capabilities”窗格中。Apple's App Store Connect 网站上应用的“应用信息”页面的“常规信息”部分中也显示软件包 ID。
  4. (可选)

    如果您的应用在 Apple App Store 中发布,请输入该应用的 App Store ID。商店 ID 是每个 Apple App Store 网址中包含的一个数字字符串。

    1. 在 iOS 或 iPadOS 设备上打开 Apple App Store 应用
    2. 搜索您的应用。
    3. 选择“分享”按钮(方形和向上箭头)。
    4. 选择复制链接
    5. 将链接粘贴到文本编辑器中。App Store ID 是网址的最后一部分。

      示例:https://apps.apple.com/app/google/id284815942

  5. (可选)

    输入您的团队 ID。如需了解详情,请参阅 Apple 开发者帐号文档中的查找您的团队 ID

  6. 点击创建
超宽带
  1. 选择通用 Windows 平台应用类型。
  2. 输入 OAuth 客户端的名称。此名称会显示在项目的 Credentials page 中,以标识客户端。
  3. 输入应用的 Microsoft Store ID(12 个字符)。您可以在 Microsoft 合作伙伴中心的“应用管理”部分的应用身份页面上找到此值。
  4. 点击创建

对于 UWP 应用,自定义 URI 的协议网址不能超过 39 个字符。

环回 IP 地址(macOS、Linux、Windows 桌面)

如需使用此网址接收授权代码,您的应用必须监听本地网络服务器。这一点在许多(但不是所有)平台上都可以实现。但是,如果您的平台支持的话,那么我们便是推荐获取授权代码的机制。

当应用收到授权响应时,为获得最佳可用性,它应通过显示一个 HTML 页面来指示用户关闭浏览器并返回您的应用。

建议用途 macOS、Linux 和 Windows 桌面应用(但不包括通用 Windows 平台)应用
表单值 将应用类型设置为桌面应用

手动复制/粘贴

确定访问权限范围

借助范围,您的应用可以仅请求访问所需的资源,同时还能控制用户向您的应用授予的访问权限。因此,请求的范围数量与征得用户同意的可能性之间是反向的。

在开始实现 OAuth 2.0 授权之前,我们建议您确定您的应用需要访问的权限范围。

OAuth 2.0 API Scopes 文档包含可用于访问 Google API 的完整范围列表。

获取 OAuth 2.0 访问令牌

以下步骤显示了您的应用如何与 Google 的 OAuth 2.0 服务器进行交互,以获取用户同意执行 API 请求。您的应用必须获得上述同意后,才能执行需要用户授权的 Google API 请求。

第 1 步:生成代码验证程序和验证

Google 支持代码交换密钥 (PKCE) 协议,可使安装的应用流程更安全。系统会为每个授权请求创建一个唯一代码验证程序,并将其转换后的值(称为“code_challenge”)发送到授权服务器以获取授权代码。

创建代码验证程序

code_verifier 是使用非保留字符 [A-Z] / [a-z] / [0-9] / "-" / "." / "_" / "~",长度不超过 43 个字符且长度不超过 83 个字符且长度很高的加密熵随机字符串。

代码验证程序应具有足够的熵,使得猜测值时不切实际。

创建代码验证

支持创建代码质询的两种方法。

代码质询生成方法
S256(推荐) 代码验证是代码验证程序的 Base64网址(无填充)编码 SHA256 哈希。
code_challenge = BASE64URL-ENCODE(SHA256(ASCII(code_verifier)))
普通 代码验证次数与上面生成的代码验证程序的值相同。
code_challenge = code_verifier

第 2 步:向 Google 的 OAuth 2.0 服务器发送请求

要获取用户授权,请通过 https://accounts.google.com/o/oauth2/v2/auth 向 Google 的授权服务器发送请求。此端点会处理活跃会话查询,对用户进行身份验证并征得用户同意。端点只能通过 SSL 访问,并且会拒绝 HTTP(非 SSL)连接。

对于授权的应用,授权服务器支持下列查询字符串参数:

参数
client_id 必需

您的应用的客户端 ID。您可以在 API ConsoleCredentials page中找到此值。

redirect_uri 必需

确定 Google 的授权服务器如何向您的应用发送响应。安装的应用可以使用多种重定向选项,而且您在设置授权凭据时要考虑到特定的重定向方法。

该值必须与您在客户端的 API ConsoleCredentials page中配置的 OAuth 2.0 客户端的某个已获授权的重定向 URI 完全一致。如果此值与已获授权的 URI 不匹配,您会收到 redirect_uri_mismatch 错误。

下表显示了每种方法对应的 redirect_uri 参数值:

redirect_uri
自定义 URI 方案 com.example.app:redirect_uri_path

com.googleusercontent.apps.123:redirect_uri_path
  • com.example.app 是您控制下的网域的反向 DNS 表示法。自定义架构必须包含英文句点。
  • com.googleusercontent.apps.123 是客户端 ID 的反向 DNS 表示法。
  • redirect_uri_path 是可选的路径组件,例如 /oauth2redirect。请注意,此路径应以单个斜杠开头,这与常规 HTTP 网址不同。
环回 IP 地址 http://127.0.0.1:porthttp://[::1]:port

在您的平台中查询相关的环回 IP 地址,并在随机可用端口上启动 HTTP 监听器。将 port 替换为您的应用侦听的实际端口号。

response_type 必需

确定 Google OAuth 2.0 端点是否会返回授权代码。

将已安装应用的参数值设为 code

scope 必需

用空格分隔的范围列表,用于标识您的应用可以代表用户访问的资源。这些值会告知用户 Google 向用户显示的同意屏幕。

通过范围,您的应用可以仅请求访问所需的资源,同时还能控制用户向您的应用授予的访问权限。因此,请求的范围数量与征得用户同意的可能性之间是相反的。

code_challenge 推荐

指定编码 code_verifier,它将在授权代码交换期间用作服务器端质询。有关详情,请参阅上文的创建代码验证部分。

code_challenge_method 推荐

指定用于对 code_verifier(用于授权代码交换期间使用的编码)进行编码的方法。此参数必须与上述 code_challenge 参数搭配使用。如果包含 code_challenge 的请求中不存在 code_challenge_method,则其值默认为 plain。此参数唯一支持的值是 S256plain

state 推荐

指定应用用于维护授权请求和授权服务器响应之间的状态的任何字符串值。在用户同意或拒绝您的应用的访问请求之后,服务器会返回您在 redirect_uri 的网址片段标识符 (#) 中作为 name=value 对发送的确切值。

此参数可用于多种用途,例如将用户定向至应用中的正确资源、发送 Nonce 以及减少跨网站请求伪造。由于您的 redirect_uri 可以猜测,因此使用 state 值可以提高传入连接是否是身份验证请求的结果。如果您生成了随机字符串或对捕获客户端状态的 Cookie 或其他值进行了哈希处理,则可以验证响应以进一步确保请求和响应来自同一浏览器,从而防范跨站请求伪造等攻击。如需查看有关如何创建和确认 state 令牌的示例,请参阅 OpenID Connect 文档。

login_hint 可选参数

如果您的应用知道哪个用户在尝试进行身份验证,它可以使用此参数向 Google 身份验证服务器提供提示。服务器会使用该提示简化登录流程,方法为:在登录表单中预先填写电子邮件字段,或选择相应的多帐号登录会话。

将参数值设为电子邮件地址或 sub 标识符,等同于用户的 Google ID。

授权网址示例

以下标签显示了不同重定向 URI 选项的示例授权网址。

除了 redirect_uri 参数的值之外,这些网址完全相同。这些网址还包含所需的 response_typeclient_id 参数以及可选的 state 参数。每个网址均包含换行符和空格,以方便阅读。

自定义 URI 方案

https://accounts.google.com/o/oauth2/v2/auth?
 scope=&
 response_type=code&
 state=security_token%3D138r5719ru3e1%26url%3Dhttps%3A%2F%2Foauth2.example.com%2Ftoken&
 redirect_uri=com.example.app%3A/oauth2redirect&
 client_id=client_id

环回 IP 地址

https://accounts.google.com/o/oauth2/v2/auth?
 scope=&
 response_type=code&
 state=security_token%3D138r5719ru3e1%26url%3Dhttps%3A%2F%2Foauth2.example.com%2Ftoken&
 redirect_uri=http%3A//127.0.0.1%3A9004&
 client_id=client_id

第 3 步:Google 提示用户同意

在此步骤中,用户可决定是否向应用授予所请求的访问权限。在此阶段,Google 会显示一个同意窗口,其中会显示应用的名称以及用户通过其授权凭据请求访问权限的 Google API 服务,以及要授予的访问权限范围的摘要。然后,用户可以同意向您的应用请求的一个或多个范围授予访问权限,或拒绝该请求。

在此阶段,您的应用在等待 Google OAuth 2.0 服务器作出响应,表明是否被授予任何访问权限时,在此阶段无需执行任何操作。下一步中将说明该响应。

错误

对 Google OAuth 2.0 授权端点的请求可能会显示面向用户的错误消息,而不是预期的身份验证和授权流程。下面列出了常见的错误代码和建议解决方法。

admin_policy_enforced

根据其 Google Workspace 管理员的政策,Google 帐号无法向所请求的一个或多个范围授权。请参阅 Google Workspace 管理员帮助文章控制哪些第三方应用和内部应用可以访问 Google Workspace 数据,详细了解管理员可以如何限制对所有范围或敏感范围和受限范围的访问权限,除非明确授予对 OAuth 客户端 ID 的访问权限。

disallowed_useragent

授权端点显示在 Google #OAuth 2.0 政策禁止的嵌入式用户代理中。

Android

android.webkit.WebView 中打开授权请求时,Android 开发者可能会遇到此错误消息。开发者应改用 Android 库,例如 Android 版 Google 登录或 OpenID Foundation' 的 AppAuth for Android

Android 应用会在嵌入式用户代理中打开常规网页链接,并且用户从您的网站导航到 Google 的 OAuth 2.0 授权端点时,可能会遇到此错误。开发者应允许打开操作系统的默认链接处理程序中的常规链接,其中包括 Android 应用链接处理程序或默认浏览器应用。Android 自定义标签页库也是一个受支持的选项。

iOS

iOS 和 macOS 开发者在 WKWebView 中打开授权请求时可能会遇到此错误。开发者应改用 iOS 库,例如 iOS 版 Google 登录或 OpenID Foundation' 的 AppAuth for iOS

如果 iOS 或 macOS 应用打开嵌入式用户代理中的常规网页链接,并且用户从您的网站导航到 Google 的 OAuth 2.0 授权端点,则网页开发者可能会遇到此错误。开发者应允许操作系统的默认链接处理程序(包括通用链接处理程序或默认浏览器应用)中打开常规链接。SFSafariViewController 库也是一个受支持的选项。

org_internal

请求中的 OAuth 客户端 ID 属于限制对特定 Google Cloud 组织中的 Google 帐号的访问的项目。如需详细了解此配置选项,请参阅“设置 OAuth 同意屏幕”帮助文章中的用户类型部分。

redirect_uri_mismatch

授权请求中传递的 redirect_uri 与 OAuth 客户端 ID 的授权 URI 不匹配。在 Google API Console Credentials page中查看已获授权的重定向 URI。

对于客户端类型,传递的 redirect_uri 可能无效。

第 4 步:处理 OAuth 2.0 服务器响应

应用接收授权响应的方式取决于其使用的重定向 URI 方案。无论采用哪种方案,响应都会包含授权代码 (code) 或错误 (error)。例如,error=access_denied 表示用户拒绝了请求。

如果用户向您的应用授予访问权限,您可以使用授权代码交换访问令牌和刷新令牌,如下一步所述。

第 5 步:交换刷新令牌和访问令牌的授权代码

如需用访问令牌交换授权代码,请调用 https://oauth2.googleapis.com/token 端点并设置以下参数:

字段
client_id 从 API ConsoleCredentials page获取的客户端 ID。
client_secret 从 API ConsoleCredentials page获取的客户端密钥。
code 初始请求返回的授权代码。
code_verifier 您在第 1 步中创建的代码验证程序。
grant_type 如 OAuth 2.0 规范中所定义,此字段的值必须设置为 authorization_code
redirect_uri 针对给定 client_id,在 API ConsoleCredentials page 中为您的项目列出的其中一个重定向 URI。

以下代码段显示了一个示例请求:

POST /token HTTP/1.1
Host: oauth2.googleapis.com
Content-Type: application/x-www-form-urlencoded

code=4/P7q7W91a-oMsCeLvIaQm6bTrgtp7&
client_id=your_client_id&
client_secret=your_client_secret&
redirect_uri=http%3A//127.0.0.1%3A9004&
grant_type=authorization_code

Google 通过返回包含短期访问令牌和刷新令牌的 JSON 对象响应此请求。

响应包含以下字段:

字段
access_token 您的应用发送的用于授权 Google API 请求的令牌。
expires_in 访问令牌的剩余生命周期(以秒为单位)。
id_token 注意:只有在您的请求包含身份范围(例如 openidprofileemail)时,才会返回此属性。该值是一个 JSON Web 令牌 (JWT),包含有关用户的数字签名身份信息。
refresh_token 可用于获取新访问令牌的令牌。除非用户撤消访问权限,否则刷新令牌会一直有效。 请注意,系统始终会为已安装的应用返回刷新令牌。
scope access_token 授予的访问权限范围,表示为以空格分隔且区分大小写的字符串列表。
token_type 返回的令牌类型。此时,此字段的值始终设置为 Bearer

以下代码段显示了一个响应示例:

{
  "access_token": "1/fFAGRNJru1FTz70BzhT3Zg",
  "expires_in": 3920,
  "token_type": "Bearer",
  "scope": "https://www.googleapis.com/auth/drive.metadata.readonly",
  "refresh_token": "1//xEoDL4iW3cxlI7yDbSRFYNG01kVKM2C-259HOF2aQbI"
}

调用 Google API

在您的应用获得访问令牌后,您可以使用该令牌代表指定的用户帐号调用 Google API(如果已授予 API 所需的访问权限范围)。为此,您可以在向 API 发出的请求中添加访问令牌,具体方法是包含 access_token 查询参数或 Authorization HTTP 标头 Bearer 值。请尽可能使用 HTTP 标头,因为查询字符串通常会显示在服务器日志中。在大多数情况下,您可以使用客户端库设置对 Google API 的调用(例如,调用 Drive Files API 时)。

您可以访问 OAuth 2.0 Playground,试用所有 Google API 并查看其范围。

HTTP GET 示例

使用 Authorization: Bearer HTTP 标头调用 drive.files 端点 (Drive Files API) 的方式可能如下所示。请注意,您需要指定自己的访问令牌:

GET /drive/v2/files HTTP/1.1
Host: www.googleapis.com
Authorization: Bearer access_token

下面是使用 access_token 查询字符串参数,对经过身份验证的用户调用的同一 API:

GET https://www.googleapis.com/drive/v2/files?access_token=access_token

curl 示例

您可以使用 curl 命令行应用测试这些命令。下面是一个使用 HTTP 标头选项(首选)的示例:

curl -H "Authorization: Bearer access_token" https://www.googleapis.com/drive/v2/files

或者,查询字符串参数选项:

curl https://www.googleapis.com/drive/v2/files?access_token=access_token

刷新访问令牌

访问令牌会定期过期,并在相关 API 请求中失效。如果您已请求离线访问与令牌关联的范围,则可以刷新访问令牌,而无需提示用户授予权限(包括当用户不在时)。

如需刷新访问令牌,您的应用会向 Google 的授权服务器 (https://oauth2.googleapis.com/token) 发送 HTTPS POST 请求,其中包含以下参数:

字段
client_id 通过 API Console获取的客户端 ID。
client_secret API Console获得的客户端密钥。(client_secret 不适用于来自注册为 Android、iOS 或 Chrome 应用的客户端的请求。)
grant_type 根据 OAuth 2.0 规范中的定义,此字段的值必须设置为 refresh_token
refresh_token 从授权代码交换中返回的刷新令牌。

以下代码段显示了一个示例请求:

POST /token HTTP/1.1
Host: oauth2.googleapis.com
Content-Type: application/x-www-form-urlencoded

client_id=your_client_id&
client_secret=your_client_secret&
refresh_token=refresh_token&
grant_type=refresh_token

只要用户尚未撤消授予应用的访问权限,令牌服务器就会返回一个包含新访问令牌的 JSON 对象。以下代码段显示了一个响应示例:

{
  "access_token": "1/fFAGRNJru1FTz70BzhT3Zg",
  "expires_in": 3920,
  "scope": "https://www.googleapis.com/auth/drive.metadata.readonly",
  "token_type": "Bearer"
}

请注意,系统将会颁发的刷新令牌数量是有限制的:每个客户端/用户组合一个限制,所有客户端上每位用户都另一个限制。您应将刷新令牌保存在长期存储空间中,并使其一直有效。如果您的应用请求刷新令牌的次数过多,则可能会遇到这些限制,在这种情况下,较旧的刷新令牌将停止运行。

撤消令牌

在某些情况下,用户可能会想要撤消对应用的访问权限。用户可以通过访问帐号设置撤消访问权限。如需了解详情,请参阅撤消有权访问您帐号的第三方网站或应用的应用部分的支持文档。

应用还可以以编程方式撤消授予它的访问权限。在用户退订、移除应用或应用所需的 API 资源发生了显著变化的情况下,程序化撤消非常重要。也就是说,移除流程的一部分可能包含 API 请求,以确保移除之前授予应用的权限。

为了以编程方式撤消令牌,您的应用会向 https://oauth2.googleapis.com/revoke 发出请求,并将令牌添加为参数:

curl -d -X -POST --header "Content-type:application/x-www-form-urlencoded" \
        https://oauth2.googleapis.com/revoke?token={token}

该令牌可以是访问令牌,也可以是刷新令牌。如果此令牌是访问令牌且具有相应的刷新令牌,则此刷新令牌也会被撤消。

如果吊销成功处理,则响应的 HTTP 状态代码为 200。对于错误情况,系统会返回 HTTP 状态代码 400 以及错误代码。

延伸阅读

IETF 最佳做法适用于原生应用的 OAuth 2.0 确立了本文中介绍的许多最佳做法。