本文档介绍了在手机、平板电脑和计算机上安装的应用如何使用 Google 的 OAuth 2.0 端点向 Google API 授予访问权限。
OAuth 2.0 允许用户与应用共享特定数据,同时保持用户名、密码和其他信息的私密性。例如,应用可以使用 OAuth 2.0 获得用户许可,将文件存储在他们的 Google 云端硬盘中。
已安装应用会分发到各个设备,并且假定这些应用无法保管密钥。当用户出现在应用上或应用在后台运行时,他们可以访问 Google API。
此授权流程类似于网络服务器应用所使用的授权流程。主要区别在于,已安装的应用必须打开系统浏览器并提供本地重定向 URI,以处理来自 Google 授权服务器的响应。
替代方案
对于移动应用,您可能希望在 Android 或 iOS 设备上使用 Google 登录功能。Google 登录客户端库会处理身份验证和用户授权,实现起来可能比此处介绍的较低级别协议更简单。
对于在不支持系统浏览器或具备有限输入功能的设备(例如电视、游戏机、相机或打印机)上运行的应用,请参阅适用于电视和设备的 OAuth 2.0 或在电视和受限输入设备上登录。
库和示例
我们建议您使用以下库和示例实现本文档中所述的 OAuth 2.0 流程:
前提条件
为您的项目启用 API
调用 Google API 的任何应用都需要在 API Console中启用这些 API。
如需为您的项目启用该 API,请按以下步骤操作:
- Open the API Library (在 Google API Console中)。
- If prompted, select a project, or create a new one.
- API Library 列出了所有可用的 API(按产品系列和热门程度分组)。如果列表中没有显示您要启用的 API,请使用搜索功能查找该 API,或点击 API 所属的产品系列中的查看全部。
- 选择您要启用的 API,然后点击启用按钮。
- If prompted, enable billing.
- If prompted, read and accept the API's Terms of Service.
创建授权凭据
任何使用 OAuth 2.0 访问 Google API 的应用都必须拥有授权凭据,向 Google 的 OAuth 2.0 服务器证明应用的身份。以下步骤介绍了如何为您的项目创建凭据。然后,您的应用就可以使用这些凭据访问您为该项目启用的 API。
- Go to the Credentials page.
- 依次点击创建凭据 > OAuth 客户端 ID。
- 以下部分介绍了 Google 授权服务器支持的客户端类型和重定向方法。选择为应用推荐的客户端类型,为您的 OAuth 客户端命名,然后适当设置表单中的其他字段。
自定义 URI 架构(Android、iOS、UWP)
建议对 Android 应用、iOS 应用和通用 Windows 平台 (UWP) 应用使用自定义 URI 架构。
Android
- 选择 Android 应用类型。
- 输入 OAuth 客户端的名称。此名称会显示在项目的 Credentials page 中,用于标识客户端。
- 输入您的 Android 应用的软件包名称。此值在应用配置文件的
<manifest>
元素的package
属性中定义。 - 输入应用分发的 SHA-1 签名证书指纹。
- 如果您的应用使用 Google Play 应用签名,请从 Play 管理中心的“应用签名”页面复制 SHA-1 指纹。
- 如果您管理自己的密钥库和签名密钥,请使用 Java 附带的 keytool 实用程序以人类可读的格式输出证书信息。复制 keytool 输出的
Certificate fingerprints
部分中的SHA1
值。如需了解详情,请参阅 Google API for Android 文档中的对客户端进行身份验证。
- 点击创建。
iOS
- 选择 iOS 应用类型。
- 输入 OAuth 客户端的名称。此名称会显示在项目的 Credentials page 中,用于标识客户端。
- 输入应用的软件包标识符。软件包 ID 是应用的信息属性列表资源文件 (info.plist) 中 CFBundleIdentifier 键的值。该值最常显示在 Xcode 项目编辑器的“General”窗格或“Signing & Capabilities”窗格中。软件包 ID 也会显示在 Apple App Store Connect 网站上相应应用的“应用信息”页面的“常规信息”部分中。
- (可选)
如果应用在 Apple 的 App Store 中发布,请输入应用的 App Store ID。商店 ID 是每个 Apple App Store 网址中包含的一个数字字符串。
- 在 iOS 或 iPadOS 设备上打开 Apple App Store 应用。
- 搜索您的应用。
- 选择“分享”按钮(方形和向上箭头)。
- 选择复制链接。
- 将链接粘贴到文本编辑器中。App Store ID 是网址的最后一部分。
示例:
https://apps.apple.com/app/google/id284815942
- (可选)
输入您的团队 ID。如需了解详情,请参阅 Apple 开发者帐号文档中的查找您的团队 ID。
- 点击创建。
超宽带
- 选择通用 Windows 平台应用类型。
- 输入 OAuth 客户端的名称。此名称会显示在项目的 Credentials page 中,用于标识客户端。
- 输入应用的 Microsoft 商店 ID(12 个字符)。您可以在 Microsoft 合作伙伴中心的“应用管理”部分内的应用身份页面上找到此值。
- 点击创建。
对于 UWP 应用,自定义 URI 架构不得超过 39 个字符。
环回 IP 地址(macOS、Linux、Windows 桌面)
如需使用此网址接收授权代码,您的应用必须监听本地网络服务器。许多(但非全部)平台上都可以做到这一点。但是,如果您的平台支持,那么这是获取授权代码的推荐机制。
当您的应用收到授权响应时,为获得最佳易用性,它应通过显示一个 HTML 页面来指示用户关闭浏览器并返回您的应用。
建议使用方式 | macOS、Linux 和 Windows 桌面(但不是通用 Windows 平台)应用 |
表单值 | 将应用类型设置为 Desktop app。 |
手动复制/粘贴
确定访问权限范围
通过范围,您的应用可以仅请求访问所需的资源,同时还可以控制用户向您的应用授予的访问权限大小。因此,请求的范围数量与征得用户同意的可能性之间可能存在反向关系。
在开始实现 OAuth 2.0 授权之前,我们建议您确定您的应用需要访问权限的范围。
OAuth 2.0 API 范围文档包含可用于访问 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 个字符,最大 128 个字符。
代码验证程序应具有足够的熵,使得猜测值变得不切实际。
创建代码挑战
系统支持两种创建代码质询的方法。
代码质询生成方法 | |
---|---|
S256(推荐) | 代码质询是代码验证程序的 Base64网址(无填充)编码 SHA256 哈希。
|
普通 | 代码质询值与上面生成的代码验证程序值相同。
|
第 2 步:向 Google 的 OAuth 2.0 服务器发送请求
要获取用户授权,请通过 https://accounts.google.com/o/oauth2/v2/auth
向 Google 的授权服务器发送请求。此端点会处理主动会话查找,对用户进行身份验证,并征得用户同意。端点只能通过 SSL 访问,并且会拒绝 HTTP(非 SSL)连接。
对于授权的应用,授权服务器支持以下查询字符串参数:
参数 | |||||||
---|---|---|---|---|---|---|---|
client_id |
必需
应用的客户端 ID。您可以在 API Console Credentials page中找到此值。 |
||||||
redirect_uri |
必需
确定 Google 的授权服务器如何向您的应用发送响应。有多个安装选项可用于安装式应用,您在设置授权凭据时考虑到了特定的重定向方法。 该值必须与您在客户端的 API Console
Credentials page中配置的 OAuth 2.0 客户端的某个授权 URI 完全匹配。如果此值与已获授权的 URI 不匹配,您会收到 下表显示了每种方法的相应
|
||||||
response_type |
必需
确定 Google OAuth 2.0 端点是否返回授权代码。 将已安装应用的参数值设为 |
||||||
scope |
必需
以空格分隔的范围列表,用于标识您的应用可以代表用户访问的资源。这些值会通知 Google 向用户显示的同意屏幕。 通过范围,您的应用可以仅请求访问所需的资源,同时还可以控制用户向您的应用授予的访问权限大小。因此,请求的范围数量与征得用户同意的可能性之间存在反向关系。 |
||||||
code_challenge |
推荐
指定编码 |
||||||
code_challenge_method |
推荐
指定用于对在授权代码交换期间使用的 |
||||||
state |
推荐
指定您的应用用于维护授权请求与授权服务器响应之间的状态的任何字符串值。在用户同意或拒绝您的应用的访问请求之后,服务器将返回您在 您可以将此参数用于多种用途,例如将用户定向到应用中的正确资源、发送 Nonce 以及减少跨网站请求伪造。由于您的 |
||||||
login_hint |
可选
如果您的应用知道哪个用户正在尝试进行身份验证,它可以使用该参数为 Google 身份验证服务器提供提示。服务器会使用此提示来简化登录流程,具体做法是填写登录表单中的电子邮件字段,或选择相应的多帐号登录会话。 将参数值设为电子邮件地址或 |
授权网址示例
以下标签页显示了不同重定向 URI 选项的示例授权网址。
除了 redirect_uri
参数的值外,这些网址完全相同。这些网址还包含所需的 response_type
和 client_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 开发者在 android.webkit.WebView
中打开授权请求时可能会遇到此错误消息。开发者应改用 Android 库,如 Google 登录 Android 版或 OpenID Foundation 的 AppAuth for Android。
当 Android 应用在嵌入式用户代理中打开常规 Web 链接,并且用户从您的网站转到 Google 的 OAuth 2.0 授权端点时,Web 开发者可能会遇到此错误。开发者应允许操作系统的默认链接处理程序(包括 Android App Links 处理程序或默认浏览器应用)中打开常规链接。Android 自定义标签页库也受支持。
iOS
iOS 和 macOS 开发者在 WKWebView
中打开授权请求时可能会遇到此错误。开发者应改用 iOS 库,例如 iOS 版 Google 登录或 OpenID Foundation 的 AppAuth for iOS。
当 iOS 或 macOS 应用打开嵌入式用户代理中的常规 Web 链接,并且用户从您的网站转到 Google 的 OAuth 2.0 授权端点时,Web 开发者可能会遇到此错误。开发者应允许操作系统的默认链接处理程序(包括通用链接处理程序或默认浏览器应用)中打开常规链接。SFSafariViewController
库也是一个受支持的选项。
org_internal
请求中的 OAuth 客户端 ID 属于某个项目,该项目限制了对特定 Google Cloud 组织中的 Google 帐号的访问。如需详细了解此配置选项,请参阅“设置 OAuth 权限请求页面”帮助文章中的用户类型部分。
invalid_grant
如果您使用了代码验证程序和验证,则 code_callenge
参数无效或缺失。确保已正确设置 code_challenge
参数。
刷新访问令牌时,此令牌可能已过期或已失效。 再次验证用户身份,并请求用户同意以获取新令牌。如果仍看到此错误,请确保您的应用已正确配置,并且您在请求中使用了正确的令牌和参数。否则,用户帐号可能已被删除或停用。
redirect_uri_mismatch
授权请求中传递的 redirect_uri
与 OAuth 客户端 ID 的已获授权的重定向 URI 不匹配。查看 Google API Console Credentials page中已获授权的重定向 URI。
对于客户端类型,传递的 redirect_uri
可能无效。
redirect_uri
参数可能是指已废弃且不再受支持的 OAuth 带外 (OOB) 流程。请参阅迁移指南以更新您的集成。
第 4 步:处理 OAuth 2.0 服务器响应
应用收到授权响应的方式取决于其使用的重定向 URI 架构。无论采用哪种方案,响应都会包含授权代码 (code
) 或错误 (error
)。例如,error=access_denied
表示用户已拒绝请求。
如果用户向您的应用授予访问权限,您可以使用授权代码交换访问令牌和刷新令牌,如下一步中所述。
第 5 步:使用授权代码交换刷新令牌和访问令牌
如需用授权代码换取访问令牌,请调用 https://oauth2.googleapis.com/token
端点并设置以下参数:
字段 | |
---|---|
client_id |
从 API Console Credentials page获取的客户端 ID。 |
client_secret |
从 API Console Credentials page获取的客户端密钥。 |
code |
初始请求返回的授权代码。 |
code_verifier |
您在第 1 步中创建的代码验证程序。 |
grant_type |
如 OAuth 2.0 规范中所定义,此字段的值必须设置为 authorization_code 。 |
redirect_uri |
在 API Console
Credentials page 中,为给定 client_id 为您的项目列出的其中一个重定向 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://127.0.0.1:9004& grant_type=authorization_code
Google 通过返回包含短期访问令牌和刷新令牌的 JSON 对象来响应此请求。
响应包含以下字段:
字段 | |
---|---|
access_token |
您的应用发送的用于授权 Google API 请求的令牌。 |
expires_in |
访问令牌的剩余生命周期(以秒为单位)。 |
id_token |
注意:仅当您的请求包含身份范围(例如 openid 、profile 或 email )时,系统才会返回此属性。该值是一个 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 制定了此处所述的许多最佳做法。