在客户端和服务器之间使用联合登录Google、FB 等的正确方法

问题描述

我已经看到使用客户端 SDK 在 Android 和 iOS 等流行平台上解决了这个问题。我的问题是

如何

  1. 创建一个使用联合 OAuth(Google、FB、Microsoft 等)的注册,并使用它来进一步验证后续 API 调用

这是我的想法

  1. 客户端应用程序调用登录提供程序的 OAuth 对话框,并接收(在用户同意后)、访问令牌和用户 ID。
  2. 这会存储在客户端并传递给服务器。
  3. 服务器可以使用 accesstoken 验证(检索)用户信息。
  4. 服务器可以返回客户端可以在后续 API 调用中使用的 IDtoken/Refreshtoken。

我的问题是

  1. 这是正确的方法吗。
  2. 客户能否存储访问令牌(最佳实践?)
  3. 客户端能否将 accesstoken 传递给后端(最佳实践?)

是否有示例,如何在不使用 SDK 的情况下为 Google 身份验证(对于客户端和网络服务器)实现这一点。

解决方法

标准选项是在您的移动应用中实现 AppAuth pattern,这意味着它会登录并使用来自您的授权服务器 (AS) 的令牌。然后,移动应用将访问令牌发送到您的 API。

完成此操作后,通过 Google、Facebook 等登录只需更改 AS 中的配置。添加新的登录名/身份提供者不需要在您的 UI 或 API 中更改代码。

这里有 Android and iOS samples of mine 使用这种方法,您可以运行它们,也许可以从中借鉴一些想法。

他们使用 AWS Cognito 作为 AS - 如果我愿意,我可以将 Cognito 配置为使用 Google 或 Facebook 登录。此外,我可以完全控制添加到访问令牌的范围和声明 - 我的 API 可以使用它们来授权请求​​。

答案

  1. 几乎正确 - 您的客户端应用重定向到 AS 而不是 Google / Facebook 直接

  2. 是的 - 移动客户端可以将刷新令牌存储在应用程序私有的操作系​​统安全存储中,这样用户就无需在每次应用程序重新启动时登录。我的样品就是这样做的。

  3. 是 - 移动客户端使用访问令牌作为 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 的 AccountManageriOS' Keychain Services 等平台功能。

客户端能否将 accessToken 传递给后端(最佳实践?)

是的,这就是它的目的。

是否有示例,如何在不使用 SDK 的情况下为 Google 身份验证(对于客户端和网络服务器)实现这一点。

出于多种原因,我不建议这样做。首先,您的实施将不如谷歌的安全,谷歌有一个团队致力于确保他们的 SDK 是最安全的。其次,您还没有准备好尝试这个实现。从 SDK 开始,让它工作,然后回到这里。

使用 Auth0 之类的解决方案将是开始的最简单方法。

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...