问题描述
我已经看到使用客户端 SDK 在 Android 和 iOS 等流行平台上解决了这个问题。我的问题是
如何
这是我的想法
- 客户端应用程序调用登录提供程序的 OAuth 对话框,并接收(在用户同意后)、访问令牌和用户 ID。
- 这会存储在客户端并传递给服务器。
- 服务器可以使用 accesstoken 验证(检索)用户信息。
- 服务器可以返回客户端可以在后续 API 调用中使用的 IDtoken/Refreshtoken。
我的问题是
是否有示例,如何在不使用 SDK 的情况下为 Google 身份验证(对于客户端和网络服务器)实现这一点。
解决方法
标准选项是在您的移动应用中实现 AppAuth pattern,这意味着它会登录并使用来自您的授权服务器 (AS) 的令牌。然后,移动应用将访问令牌发送到您的 API。
完成此操作后,通过 Google、Facebook 等登录只需更改 AS 中的配置。添加新的登录名/身份提供者不需要在您的 UI 或 API 中更改代码。
这里有 Android and iOS samples of mine 使用这种方法,您可以运行它们,也许可以从中借鉴一些想法。
他们使用 AWS Cognito 作为 AS - 如果我愿意,我可以将 Cognito 配置为使用 Google 或 Facebook 登录。此外,我可以完全控制添加到访问令牌的范围和声明 - 我的 API 可以使用它们来授权请求。
答案
-
几乎正确 - 您的客户端应用重定向到 AS 而不是 Google / Facebook 直接
-
是的 - 移动客户端可以将刷新令牌存储在应用程序私有的操作系统安全存储中,这样用户就无需在每次应用程序重新启动时登录。我的样品就是这样做的。
-
是 - 移动客户端使用访问令牌作为 API 消息凭据
图书馆
我同意您的观点 - 避免在您的应用中使用 Google/Facebook 库。但是,建议使用受人尊敬的 AppAuth 库 - 一旦集成,您的应用将与任何 AS 兼容,并将支持其所有身份验证流程。
出于兴趣,AppAuth 模式甚至可能支持未来的高级场景,例如 App2App,因为 AS 可以联合到来自另一家公司的 AS(尽管我现在怀疑这是否与您相关)。
学习曲线
最后值得一提的是,实现 AppAuth 很棘手 - 有一些烦恼 - 但一旦完成,架构就会处于良好状态。
,首先,任何调用 Google API 的应用程序都需要在 API 控制台中启用这些 API。
现在,任何使用 OAuth 2.0
访问 Google API 的应用程序都必须具有向 Google 的 OAuth 2.0 服务器标识应用程序的授权凭据。
对于凭据,请转到 Credentials Page,然后根据您的申请填写表格。
注意:Google 建议您设计应用的身份验证端点,以便您的应用不会向页面上的其他资源公开授权代码。
获取凭据后,从 API 控制台下载 client_secret.json
文件,并将文件安全地存储在只有您的应用程序可以访问的位置。
对于 HTTP/REST,无需安装任何库来调用 oAuth 2.0
Google 的 OAuth 2.0 端点位于 https://accounts.google.com/o/oauth2/v2/auth
。此端点只能通过 HTTPS
访问。普通的 HTTP
连接被拒绝。
作为客户端,对于基本身份验证,您唯一需要做的就是在 HTTP 请求中包含一个 Authorization 标头,由用户名和密码组成,用冒号分隔,然后进行 Base64 编码。例如,在 Ruby (1.9) 中使用 RestClient:
require 'restclient'
require 'base64'
auth = "Basic " + Base64::strict_encode64("#{username}:#{password}")
response = RestClient.get("https://myhost/resource",:authorization=>auth)
令牌值对客户端是不透明的,但可以由资源服务器解码,以便它可以检查客户端和用户是否有权访问所请求的资源。
Authorization: Bearer <TOKEN_VALUE>
将用户发送到 Google 的 OAuth 2.0 服务器。示例网址:
https://accounts.google.com/o/oauth2/v2/auth?
scope=https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fdrive.metadata.readonly&
access_type=offline&
include_granted_scopes=true&
state=state_parameter_passthrough_value&
redirect_uri=http%3A%2F%2Foauth2.example.com%2Fcallback&
response_type=code&
client_id=client_id
请求访问令牌。示例:
POST /oauth2/v4/token HTTP/1.1
Host: www.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=https://oauth2.example.com/code&
grant_type=authorization_code
使用 API。示例:
GET /drive/v2/files HTTP/1.1
Authorization: Bearer <access_token>
Host: www.googleapis.com/
,
这是正确的方法吗。
是的,差不多。您正在描述标准不记名令牌授权。访问和 ID 令牌在很短的时间范围内过期,您必须使用长期存在的刷新令牌来获取新令牌。访问令牌允许您获得访问权,刷新令牌仅用于引导令牌。
客户端能否存储访问令牌(最佳实践?)
是的。您必须存储一个 OAuth 刷新令牌。您可以存储 ID 和访问令牌(而不是将它们保存在内存中。)
在网络上,您不应该使用本地存储。相反,use an httpOnly cookie。
在移动设备上,使用 Android 的 AccountManager 或 iOS' Keychain Services 等平台功能。
客户端能否将 accessToken 传递给后端(最佳实践?)
是的,这就是它的目的。
是否有示例,如何在不使用 SDK 的情况下为 Google 身份验证(对于客户端和网络服务器)实现这一点。
出于多种原因,我不建议这样做。首先,您的实施将不如谷歌的安全,谷歌有一个团队致力于确保他们的 SDK 是最安全的。其次,您还没有准备好尝试这个实现。从 SDK 开始,让它工作,然后回到这里。
使用 Auth0 之类的解决方案将是开始的最简单方法。