如何使用多个 OAUTH 提供商在 App Engine 上安全地注册用户?

How to securely register users on App Engine using multiple OAUTH providers?

我想讨论一个常见的场景:一个应用程序想要使用多个 OAUTH 提供商授权用户,例如 Facebook、Google+ 或 Twitter。

这个问题基本上是两年前在这里 Mobile API Authentication Using Existing Web App with Multiple OAuth Providers 提出的,但一直没有得到回答,所以我会进一步详细说明。 (我将使用 Facebook 作为 OAUTH2 提供程序的示例,因此这不会变得太笼统。)

基本上,用户注册是这样工作的:OAUTH/OAUTH2 供应商通常提供一个工作流程,其中(主要是 short-lived)令牌是通过移动设备上的 AccountManager 或登录从供应商处获取的对话框,例如 "Login with Facebook" 按钮。然后通过调用 REST 端点(在 body 中或作为附加 header,从不在 URL 中)将令牌传送到 App Engine。

提供商的 AppId 和 AppSecret(此处为:Facebook)存储在 App Engine 上,App Engine 将这些添加到令牌中,然后将其发送回 Facebook 以换取 (long-lived) 令牌。

此时,客户端应用程序和 App Engine 应用程序都确定用户之前已通过 Facebook 的身份验证。此外,如果端点身份验证用于对调用进行身份验证,App Engine 可能具有用户的 Google 凭据 and/or 应用程序的 ClientId,并且 Google 保证已发出请求来自正确的客户端应用程序。

在这一点上,我们可以尝试在我们的数据存储中找到用户,如果它已经存在则让注册失败(或静默登录用户),否则创建一个记录。

到这里为止,我很确定我在正确的轨道上。问题来了:

让我们看看这个的数据存储。假设我们有两个实体:

  1. 用户实体,我们自己系统中的每个用户都在一个唯一的用户 ID 下注册。
  2. 账户实体,每个账户都在这里注册,其中一个userId字段指向用户实体。

在关系数据库术语中,我们会说我们在用户和帐户之间存在 1:n 关系。

对于我们系统中的每个用户,我们都会保留一个用户记录。在上面的示例中,我们可能有两个帐户:Facebook 和 Google,它们都指向用户,并且唯一的 Facebook 或 Google id/email 用作帐户标识符。

从技术上讲,应用程序现在可以在后续请求中使用 Facebook 或 Google 帐户。但是我们必须在每个请求中存储和查找第 3 方令牌,因为我们无法自己解密它。我们可以要求提供商这样做,但这也没有多大意义。此外,我们必须在每次请求时将提供商的帐户 ID 转换为我们自己的用户 ID。

为了解决这个问题,我很可能要么创建我们自己的令牌,要么设置我们自己的 OAUTH 提供程序,它创建一个由我们自己的系统签名的令牌,并且唯一的用户 ID 用作标识符,并且只使用它在后续请求期间令牌。

本质上它围绕 Google 的端点系统工作,但 Google 只能针对他们自己的系统进行身份验证,因此如果我们想使用更多提供商来提供 sign-in,我们将需要解决这个问题,除非任何 body 知道我们可以保留两者的工作流程,但是我们遇到了问题,我们 can/should 只在 "Authorization" header 和 REST 原则不鼓励我们使用自定义 header 来发送更多令牌。

当您的应用对用户进行身份验证时,在会话中存储一个对象,该对象包含用于访问该应用的 oauth 提供程序,以及可选的用于后续请求的令牌。

现在您可以在每次调用服务器时检查此对象。如果对象不存在 - 用户未通过身份验证,则重定向到登录页面。如果存在对象,则取令牌并使用它。

我对多个身份验证选项使用类似的方法,而不仅仅是 oauth。除了我不需要在用户通过身份验证后存储令牌 - 我在应用程序中没有用到它。