将多个用户帐户合并在一起的体系结构

我有个网站,你可以注册然后登陆。你也可以用你的 facebook,twitter 或者 linkedin 账户登录。

重要的是,用户只有一个帐户注册。因此,如果用户使用不同的方法登录,我想合并他们的帐户。解决这个问题的最好办法是什么?

例如,用户用他的 Facebook 帐户登录。我用这些数据自动为他注册了一个账户。我是否应该发送一封附有我们网站用户名和密码的电子邮件?(如果 Facebook 的政策允许的话)。我应该给他们第二个屏幕,在那里他们可以填写用户名和密码?但这并不是用你的 Facebook 账户登录的原因。它应该能简化你参与的程序。

也有可能这个用户已经在我们的网站上注册了,下次他再登陆他的 twitter 账号的时候。如何将这两个帐户合并为一个帐户?最好的办法是什么?

所以基本上我的问题是: 我有4种不同的方式一个用户成为我们网站的成员。如果一个用户决定使用多种方式,我如何确保所有这4种方式只创建一个帐户?确保它不会成为用户自己的麻烦的最佳流程是什么?


编辑:

在我提出这个问题3年后,我自己在一系列文章中给出了答案: Https://www.peternijssen.nl/social-network-authentication-setup/
Https://www.peternijssen.nl/social-network-authentication-google/
Https://www.peternijssen.nl/social-network-authentication-merging-accounts/
Https://www.peternijssen.nl/social-network-authentication-twitter-facebook/

29396 次浏览

您应该允许从 帐户登录,然后在登录时给予选项添加不同的其他帐户合并到它。

我现在面临着同样的任务。我设计出来的设计相当简单,但是效果很好。

其核心思想是,本地站点标识模型和第三方站点标识模型保持隔离,但随后进行链接。所以每个登录到站点的用户都有一个本地标识,它映射到任意数量的第三方站点标识。

本地身份记录包含最少的信息——它甚至可以是单个字段——只是一个主键。(对于我的应用程序,我不关心用户的电子邮件、姓名或出生日期——我只想知道他们是一直在登录这个账户的人。)

第三方身份包含仅与第三方身份验证相关的信息。对于 OAuth,这通常意味着一个用户标识符(如 id、 email 或用户名)和一个服务标识符(指示使用哪个站点或服务进行了身份验证)。在应用程序的其他部分,在数据库之外,该服务标识符与从该服务检索相关用户标识符的方法配对,这就是执行身份验证的方式。对于 OpenID,我们采用相同的方法,只是认证的方法更加通用(因为我们几乎总是可以执行完全相同的协议——除了我们使用不同的标识 URL,那是我们的服务标识符)。

最后,我记录了哪些第三方身份与哪些本地身份相匹配。要生成这些记录,流程如下所示:

  • 用户首次使用第三方标识登录。创建一个本地身份记录,然后创建一个第三方身份记录,然后将它们配对。
  • 在控制面板中,用户有机会通过登录到第三方服务来链接帐户。(工作原理很简单。)
  • 在用户无意中创建多个帐户的场景中,解决方案非常简单。当用户登录到其中一个帐户时,他将登录到他以前用来登录站点的另一个帐户(通过上面的控制面板特性)。Web 服务检测到这种冲突(登录用户的本地身份与链接到刚刚登录的第三方身份的本地身份不同) ,并提示用户合并帐户。

合并帐户就是合并本地身份的每个单独字段(每个应用程序都不一样,如果你的本地身份记录中只有几个字段,这应该很容易) ,然后确保链接的第三方身份与结果的本地身份相关联。

我在 Ssled.com 上看到过。这里有关于创建帐户和支持多个第三方帐户登录的多个问题。其中一些是:

  • 是否需要同时支持本地密码和第三方登录?

对于 sled.com,我决定放弃本地密码,因为它增加的价值很小,而且保护密码输入表单需要额外的成本。有许多已知的破解密码的攻击,如果你要介绍密码,你必须确保他们不容易破解。您还需要将它们存储在单向散列或类似的东西中,以防止它们被泄露。

  • 您希望在支持多个第三方帐户方面允许多大的灵活性?

听起来你已经选择了三个登录提供商: Facebook、 Twitter 和 LinkedIn。这很好,因为这意味着您正在使用 OAuth 并使用一组定义良好的可信提供程序。我不喜欢 OpenID。剩下的问题是您是否需要支持来自同一提供商的多个第三方帐户(例如,一个本地帐户与两个 Twitter 帐户链接)。我假设没有,但是如果您这样做了,您将需要在您的数据模型中适应它。

对于 Sled,我们支持使用 Facebook、 Twitter 和 Yahoo! 登录,并在每个用户帐户中存储每个帐户的密钥: {“ _ id”: “ djd99dj”,“ yahoo”: “ dj39djdj”,Twitter: “3723828732”,“ Facebook”: “12837287”}。我们设置了一系列约束,以确保每个第三方帐户只能链接到一个本地帐户。

如果要允许来自同一个第三方提供商的多个帐户,则需要使用列表或其他结构来支持这一点,并且还需要使用所有其他限制来确保唯一性。

  • 如何链接多个帐户?

当用户第一次注册您的服务时,他们首先会去第三方提供商,并返回一个经过验证的第三方 ID。然后为他们创建一个本地帐户,并收集任何其他需要的信息。我们收集他们的电子邮件地址,并要求他们选择一个本地用户名(我们试图用他们现有的用户名从其他提供商预先填充表单)。拥有某种形式的本地标识符(电子邮件、用户名)对于以后的帐户恢复非常重要。

如果浏览器没有现有帐户的会话 cookie (有效或过期) ,并且找不到所使用的第三方帐户,则服务器知道这是第一次登录。我们试图告诉用户,他们不仅仅是在登录,而是在创建一个新帐户,这样,如果他们已经有了一个帐户,他们就有希望暂停登录,而不是使用他们现有的帐户。

我们使用完全相同的流来链接其他帐户,但是当用户从第三方返回时,使用有效的会话 cookie 来区分将新帐户链接到登录操作的尝试。我们只允许每种类型的一个第三方帐户,如果已经有一个链接,阻止行动。这应该不是问题,因为如果您已经有了一个(每个提供者) ,那么链接新帐户的接口将被禁用,但这只是以防万一。

  • 如何合并帐户?

如果用户试图链接一个新的已经链接到本地帐户的第三方帐户,你只需提示他们确认他们想要合并两个帐户(假设你可以处理这样的合并与您的数据集-往往说起来容易做起来难)。您还可以为他们提供一个特殊的按钮来请求合并,但实际上,他们所做的只是链接另一个帐户。

这是一个非常简单的状态机。用户通过第三方帐户 ID 从第三方返回。您的数据库可以处于以下三种状态之一:

  1. 该帐户链接到本地帐户,并且没有会话 cookie 现在—— > 登入
  2. 该帐户与一个本地帐户和一个 存在会话 cookie —— > Merge
  3. 该帐户未链接到 本地帐户,没有会话 cookie-> 注册
  4. 那个 帐户没有链接到本地帐户,而会话 cookie 现时-> 连结其他帐户

    • 如何与第三方提供商进行帐户恢复?

这里还是实验区。我还没有看到一个完美的用户体验,因为大多数服务都提供了一个本地密码旁边的第三方帐户,因此重点是“忘记我的密码”用例,而不是其他一切可能出错。

对于 Sled,我们选择使用“需要帮助登录吗?”当你点击的时候,问用户他们的电子邮件或用户名。我们查找它,如果我们发现一个匹配的帐户,电子邮件用户一个链接,可以自动登录到服务(好一次)。一旦进入,我们把他们直接带到帐户链接页面,告诉他们,他们应该看一看,并可能链接额外的帐户,并向他们展示第三方帐户,他们已经链接。

这两种自动合并账户的方法都留下了一个非常大的漏洞,使得有人可以接管一个账户。当他们向注册用户提供合并选项时,他们似乎都假设用户就是他们所说的那个人。

我的建议是,在执行合并之前,请求用户通过一个已知的 Identity Provider 进行身份验证,以验证用户的身份。

示例: 用户 A 使用 Facebook 身份注册。一段时间后,他们回到您的网站,并尝试访问与 WindowsLiveID,并开始注册过程。您的网站将提示用户 A 与... 它看起来像你已经注册了 Facebook 以前。请登录 Facebook (提供链接) ,我们可以合并您的 Windows Live ID 与您现有的配置文件。

另一种方法是在合并身份时,在用户必须提供的初始注册上存储共享秘密(密码/个人问题) ,但这会让您重新进入存储共享秘密的业务。这还意味着您必须处理用户不记得共享秘密和随之而来的工作流的场景。

我倾向于发现很多站点合并基于 电子邮件作为重叠加入因素。

我可以看到这是一个可行的选择,但它再次取决于你对如何合并的偏好。电子邮件地址是人们用来验证网站上一些重要信息变化的主要方式,比如更改密码、终止服务、帐户余额低等等。.它几乎就像网络的社会安全号码系统,但具有交流的能力。文化: 我认为,假设电子邮件是 OAuth 身份验证服务中一个非常独特的身份是合理的。当然,这是 Facebook 和 Google 的登录表单所要求的。

我现在的思维方式。

登录页面有3个选项

  • 你自己网站的会员资格
  • 登陆 facebook
  • 用谷歌登录

1)用户第一次登录: 触发一个注册流程,其中第一次创建和填充一个帐户。

 if the user logins using Facebook (or whatever 3rd party login)
1) call the Facebook api asking for their information (email, name, etc...)
2) create an account membership entry in your database somewhat like this


Table = Users
[ UserId   |       Email             | Password ]
[    23     | "newuser@coolmail.com" |  *null*  ]


3) create an external auths entry like so
*ProviderUserId is the unique id of that user on the provider's site


Table = ExternalAuths
[ ExternalAuthId  |  User_UserId   | ProviderName |   ProviderUserId  ]
[    56           |      23        |   Facebook   |  "max.alexander.9"]


if the user wants to create an account with your own registration it would just be this


Table = Users
[ UserId   |       Email           |   Password  ]
[    23     | newuser@coolmail.com |  myCoolPwd  ]

2)在其他时间,用户回来,但决定点击谷歌登录

      1) call the Google api asking for their information (email, name, etc...)


2) once you get the email, match it up to the userId entry with the existing email


3) create an additional External auth entry as such


Table = ExternalAuths
[ ExternalAuthId  |  User_UserId   | ProviderName |   ProviderUserId  ]
[    56           |      23        |   Facebook   |  "max.alexander.9"]
[    57           |      23        |    Google    |  "1234854368"     ]

3)现在你已经合并了你信任的账户,你的数据库条目中的电子邮件和你从外部登录中信任的邮件是一样的。

因此,对于后续的登录

那么,如果您首先有外部登录,然后希望用户稍后能够使用密码登录,那么该怎么办呢?

我看到了两种简单的方法

  • 当从外部身份验证创建帐户时,在任何第一次登录时,要求他们输入密码,以完成他们进入应用程序的第一个条目

  • 如果他们已经注册使用 Facebook 或谷歌第一,然后不知怎么想注册使用自己的网站的注册表格。检测他们输入的电子邮件地址是否已经存在,要求他们输入密码,并在注册完成后向他们发送电子邮件确认。

大多数帖子都很老了,我猜 Google 的免费 Firebase 认证服务还没有出现。在使用 OAuth 进行验证之后,将 OAuth 令牌传递给它,并获得一个惟一的用户 ID,您可以将其存储以供参考。支持的供应商有 Google、 Facebook、 Twitter、 GitHub,还有一个注册自定义和匿名供应商的选项。

很好的答案和上面的资源。我的贡献总结在这里... https://github.com/JavascriptMick/learntree.org/blob/master/design/Schema.md

TLDR: 独立的 Account 和 Person 模式。 Account,Email 和 OAuth 的2个变体。

帐户-认证-> 个人