如何使用多个 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 保证已发出请求来自正确的客户端应用程序。
在这一点上,我们可以尝试在我们的数据存储中找到用户,如果它已经存在则让注册失败(或静默登录用户),否则创建一个记录。
到这里为止,我很确定我在正确的轨道上。问题来了:
让我们看看这个的数据存储。假设我们有两个实体:
- 用户实体,我们自己系统中的每个用户都在一个唯一的用户 ID 下注册。
- 账户实体,每个账户都在这里注册,其中一个userId字段指向用户实体。
在关系数据库术语中,我们会说我们在用户和帐户之间存在 1:n 关系。
对于我们系统中的每个用户,我们都会保留一个用户记录。在上面的示例中,我们可能有两个帐户:Facebook 和 Google,它们都指向用户,并且唯一的 Facebook 或 Google id/email 用作帐户标识符。
从技术上讲,应用程序现在可以在后续请求中使用 Facebook 或 Google 帐户。但是我们必须在每个请求中存储和查找第 3 方令牌,因为我们无法自己解密它。我们可以要求提供商这样做,但这也没有多大意义。此外,我们必须在每次请求时将提供商的帐户 ID 转换为我们自己的用户 ID。
为了解决这个问题,我很可能要么创建我们自己的令牌,要么设置我们自己的 OAUTH 提供程序,它创建一个由我们自己的系统签名的令牌,并且唯一的用户 ID 用作标识符,并且只使用它在后续请求期间令牌。
- 这是一个好方法吗?是否有人body 使用不同的更好的工作流程?有人body 发现此设计存在安全缺陷吗?
本质上它围绕 Google 的端点系统工作,但 Google 只能针对他们自己的系统进行身份验证,因此如果我们想使用更多提供商来提供 sign-in,我们将需要解决这个问题,除非任何 body 知道我们可以保留两者的工作流程,但是我们遇到了问题,我们 can/should 只在 "Authorization" header 和 REST 原则不鼓励我们使用自定义 header 来发送更多令牌。
当您的应用对用户进行身份验证时,在会话中存储一个对象,该对象包含用于访问该应用的 oauth 提供程序,以及可选的用于后续请求的令牌。
现在您可以在每次调用服务器时检查此对象。如果对象不存在 - 用户未通过身份验证,则重定向到登录页面。如果存在对象,则取令牌并使用它。
我对多个身份验证选项使用类似的方法,而不仅仅是 oauth。除了我不需要在用户通过身份验证后存储令牌 - 我在应用程序中没有用到它。
我想讨论一个常见的场景:一个应用程序想要使用多个 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 保证已发出请求来自正确的客户端应用程序。
在这一点上,我们可以尝试在我们的数据存储中找到用户,如果它已经存在则让注册失败(或静默登录用户),否则创建一个记录。
到这里为止,我很确定我在正确的轨道上。问题来了:
让我们看看这个的数据存储。假设我们有两个实体:
- 用户实体,我们自己系统中的每个用户都在一个唯一的用户 ID 下注册。
- 账户实体,每个账户都在这里注册,其中一个userId字段指向用户实体。
在关系数据库术语中,我们会说我们在用户和帐户之间存在 1:n 关系。
对于我们系统中的每个用户,我们都会保留一个用户记录。在上面的示例中,我们可能有两个帐户:Facebook 和 Google,它们都指向用户,并且唯一的 Facebook 或 Google id/email 用作帐户标识符。
从技术上讲,应用程序现在可以在后续请求中使用 Facebook 或 Google 帐户。但是我们必须在每个请求中存储和查找第 3 方令牌,因为我们无法自己解密它。我们可以要求提供商这样做,但这也没有多大意义。此外,我们必须在每次请求时将提供商的帐户 ID 转换为我们自己的用户 ID。
为了解决这个问题,我很可能要么创建我们自己的令牌,要么设置我们自己的 OAUTH 提供程序,它创建一个由我们自己的系统签名的令牌,并且唯一的用户 ID 用作标识符,并且只使用它在后续请求期间令牌。
- 这是一个好方法吗?是否有人body 使用不同的更好的工作流程?有人body 发现此设计存在安全缺陷吗?
本质上它围绕 Google 的端点系统工作,但 Google 只能针对他们自己的系统进行身份验证,因此如果我们想使用更多提供商来提供 sign-in,我们将需要解决这个问题,除非任何 body 知道我们可以保留两者的工作流程,但是我们遇到了问题,我们 can/should 只在 "Authorization" header 和 REST 原则不鼓励我们使用自定义 header 来发送更多令牌。
当您的应用对用户进行身份验证时,在会话中存储一个对象,该对象包含用于访问该应用的 oauth 提供程序,以及可选的用于后续请求的令牌。
现在您可以在每次调用服务器时检查此对象。如果对象不存在 - 用户未通过身份验证,则重定向到登录页面。如果存在对象,则取令牌并使用它。
我对多个身份验证选项使用类似的方法,而不仅仅是 oauth。除了我不需要在用户通过身份验证后存储令牌 - 我在应用程序中没有用到它。