合并多个用户帐户的体系结构


176

好的,我有一个网站,您可以在此注册自己并登录。您也可以使用您的Facebook,Twitter或linkedin帐户登录。

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

例如,用户使用他的Facebook帐户登录。我使用这些数据自动为他注册一个帐户。我应该发送包含我们网站用户名和密码的电子邮件吗?(如果使用Facebook的政策可以的话)。我应该给他们第二个屏幕,他们可以在其中输入用户名和密码吗?但这不是用您的Facebook帐户登录的想法。它应该简化您的参与程序。

用户也有可能在我们的网站上注册了自己,并且下次他使用自己的Twitter帐户登录时。如何将这两个帐户合并为一个?最好的方法是什么?

所以基本上我的问题是:用户有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/


7
当然,最好是通过允许使用诸如Stack Overflow之类的多种登录方法来阻止用户首先拥有多个帐户,但是即使SO也具有主持人合并帐户的能力。我向任何可以描述允许这样做的体系结构的人提供悬赏。必须有一个比“更新帖子集UserID = 2,其中UserID = 1”更好的解决方案
David Boike

电子邮件和电话可以用作合并密钥,还有其他吗?
Wuaner '16

您好,您提供的链接似乎无效。仅进入网站首页
vigamage

更新了链接。文章虽然有6岁。
PT

Answers:


120

目前,我面临着完全相同的任务。我制定的设计相当简单,但是效果很好。

核心思想是将本地站点标识和第三方站点标识的模型保持隔离,但以后将链接起来。因此,每个登录到该站点的用户都具有一个本地身份,该身份映射到任意数量的第三方站点身份。

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

第三方身份包含仅与第三方身份验证有关的信息。对于OAuth,这通常表示用户标识符(例如ID,电子邮件或用户名)和服务标识符(指示使用哪个网站或服务进行身份验证)。在应用程序的其他部分中,在数据库外部,该服务标识符与一种用于从该服务中检索相关用户标识符的方法配对,这就是执行身份验证的方法。对于OpenID,我们采用相同的方法,不同之处在于身份验证的方法更加通用(因为我们几乎总是可以执行完全相同的协议-除了我们使用不同的身份URL,这就是我们的服务标识符)。

最后,我保留将哪些第三方身份与什么本地身份配对的记录。要生成这些记录,流程如下所示:

  • 用户首次使用第三方身份登录。创建本地身份记录,然后创建第三方身份记录,然后将它们配对。
  • 在控制面板中,为用户提供了通过登录第三方服务来链接帐户的机会。(这很简单。)
  • 在用户不经意间创建多个帐户的情况下,解决方案非常简单。当用户登录其中一个帐户时,他登录了先前用于登录站点的另一个帐户(通过上面的控制面板功能)。Web服务检测到此冲突(已登录用户的本地标识与链接到刚登录的第三方标识的本地标识不同),并提示用户进行帐户合并。

合并帐户是合并本地身份的每个单独字段的方法(每个字段随应用程序的不同而不同,如果您的本地身份记录中只有几个字段,应该很容易),然后确保链接的第三方身份与最终的本地身份相关联。


1
这是一个非常好的解决方案(我喜欢自动检测本地身份冲突的想法)!我想知道您是否找到一种方法,将用户自动登录到首次登录该应用程序后链接的“额外”帐户。用户是否需要在每次访问时分别登录每个帐户(如果尚未与该提供程序进行有效会话)?
亚历山德拉

@Alexandra“额外帐户”是什么意思?您是否在问用户通过几个不同的身份验证器登录到应用程序并为每个身份验证器创建一个新的本地身份时会发生什么?
cheeken 2012年

我认为这值得适当的澄清和它自己的问题:stackoverflow.com/questions/11060368/…–
Alexandra

3
虽然有问题,但是如果用户使用相同的电子邮件地址注册到站点怎么办?我们是否提示他们电子邮件已经存在(来自第三方模型的电子邮件),还是仍将其注册到站点,然后合并这些帐户?
user962206

@ user962206出于隐私原因,许多服务都不会为您提供“真实”电子邮件地址。例如,据我所知,Twitter不会给您任何电子邮件地址,据我所知,Facebook会给您“ user.name@facebook.com”,我怀疑有人会使用该地址进行注册。
kapex 2013年

44

我倾向于发现许多基于电子邮件的网站合并是重叠的因素。

我可以看到这是一个可行的选择,但同样取决于您对合并的偏好。电子邮件地址是人们用来验证您网站上某些重要信息更改(例如更改密码,服务终止,帐户余额不足等)的主要方式。 。从文化上讲:我认为假设电子邮件是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)在其他时间,用户回来了,但决定单击Google登录名

      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注册了,那么不知何故想要使用您自己网站的注册表格进行注册。检测他们输入的电子邮件地址是否已经存在,要求他们输入密码,并在注册完成后向他们发送电子邮件确认。


1
当您使用外部身份验证方案(Facebook,Google,Twitter等)时,您将永远无法访问外部提供商密码。上面示例中的密码是您的OWN Web应用的密码。
Max Alexander

6
Twitter不向用户提供电子邮件。因此,在首次身份验证后,如果Twitter UserId不存在,请提示他输入电子邮件和密码。如果存在电子邮件和密码,请链接帐户。如果没有,请存储电子邮件和密码以进行无缝的后续身份验证。这有帮助吗?
Max Alexander

1
附带说明,现在可以为您的Twitter应用请求权限以获取用户的电子邮件地址。
Sunil D.

2
Facebook是否会让人们验证他们的电子邮件?例如,我知道Github不会。恶意用户可以使用他人的电子邮件名注册Github,然后使用此策略访问您网站上的帐户。(Github的API会告诉您他们的电子邮件是否已通过验证-您可以拒绝在未经验证的电子邮件地址上通过Github进行身份验证的任何人)
Matthew Moisen

6
如果用户通过社交媒体注册,在社交媒体中编辑其电子邮件地址,其他人使用相同的电子邮件地址并在社交媒体中注册,然后登录,则该用户将与其他帐户合并,这是安全漏洞。这是极不可能的,但仍然违反。还是我错过了一些东西。
Shane

35

我已经通过sled.com进行了此操作。在创建帐户和支持多个第三方帐户登录方面,这里存在多个问题。他们之中有一些是:

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

对于sled.com,我决定删除本地密码,因为它增加了很小的价值,并且增加了保护密码输入表单的额外成本。有许多已知的破坏密码的攻击,如果要引入密码,则必须确保它们不容易破解。您还需要将它们存储在单向哈希或类似方式中,以防止它们泄漏。

  • 您要在支持多个第三方帐户中允许多少灵活性?

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

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

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

  • 如何关联多个帐户?

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

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

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

  • 如何合并账户?

如果用户尝试链接已经链接到本地​​帐户的新第三方帐户,则只需提示他们确认要合并这两个帐户(假设您可以使用数据集处理此类合并-通常更容易地说比完成)。您还可以为他们提供一个特殊的按钮来请求合并,但是实际上,他们所做的只是链接另一个帐户。

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

  1. 该帐户已链接到本地​​帐户,并且没有会话cookie->登录
  2. 该帐户已链接到本地​​帐户,并且存在会话cookie->合并
  3. 该帐户未链接到本地​​帐户,并且没有会话cookie->注册
  4. 该帐户未链接到本地​​帐户,并且存在会话cookie->链接其他帐户

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

这仍然是实验领域。我还没有看到完美的UX,因为大多数服务都在第三方帐户旁边提供了本地密码,因此着眼于“忘记密码”用例,而不是其他所有可能出错的地方。

对于Sled,我们选择使用“需要帮助登录吗?” 当您单击时,询问用户其电子邮件或用户名。我们会查找它,如果找到匹配的帐户,请给该用户发送电子邮件链接,该链接可以自动将其登录到该服务(一次有效)。进入后,我们将他们直接带到帐户链接页面,告诉他们应该看一下并可能链接其他帐户,并向他们显示他们已链接的第三方帐户。


这个解决方案对我来说更好,谢谢!
罗伊·肖阿

2
会话cookie不足以识别用户。如果另一个用户使用相同的设备怎么办?
DeepBlue '16

23

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

我建议减轻漏洞的建议是,在执行合并以验证用户身份之前,先请求用户与已知身份提供者之一进行身份验证。

示例:用户A以Facebook身份注册。稍后,他们将返回您的站点并尝试使用Windows Live ID进行访问并开始注册过程。您的网站将提示用户A具有...好像您以前已在Facebook上注册。请使用Facebook登录(提供链接),我们可以将您的Windows Live ID与您现有的配置文件合并。

另一种选择是在合并身份时用户必须提供的初始注册上存储共享机密(密码/个人问题),但是,这会使您重新从事存储共享机密的工作。这也意味着您必须处理用户不记得共享机密以及随之而来的工作流程的情况。


如果您没有收到提供商的电子邮件地址,该怎么办?
fred.kassi 2015年

1

大多数帖子都已经很老了,我想Google的免费Firebase身份验证服务还没有出现。使用OAuth验证后,您将OAuth令牌传递给它,并获得一个唯一的用户ID,您可以将其存储以供参考。受支持的提供商包括Google,Facebook,Twitter,GitHub,并且可以选择注册自定义提供商和匿名提供商。


在有些用例中,firebase毫无意义。例如,具有多个登录名的Intranet系统
。– Bostwick


-4

您应该允许从一个帐户登录,然后在登录时提供添加其他帐户以与其合并的选项。


4
如果用户不这样做,并且发现自己拥有4个不同的帐户,将会发生什么?在这种情况下,如何创建允许合并的体系结构?
David Boike

根据您的需求,这实际上可能是一个有效的建议。我只想警告那些认为以后可以合并或链接帐户的人:如果您认为以后可能需要这样做,那么您将需要为数据库设计的开始做好准备:选项是具有一个UserGroup和一个UserMapping。您可以将OAuth用户ID或“电子邮件和密码”用户ID映射到UserGroup。
BumbleB2na '16
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.