我认为基本上,如果正确处理所有情况,这可能会非常复杂,除非您选择下面的选项 1(即使如此,也有一些问题需要考虑,我稍后概述)。抱歉这个答案太长了!
我假设你已经做了这样的事情:
https://github.com/plataformatec/devise/wiki/OmniAuth:-概述 https://github.com/plataformatec/devise/wiki/OmniAuth:-Overview
到目前为止,这可以帮助您解决一些问题,但无法解决您遇到的问题。
我这样做的方式是,我有一个具有多个身份的用户。身份存储外部服务的名称、它告诉您的用户 ID 以及您想要的任何其他内容。这意味着同一用户可以使用多个身份登录(twitter、Facebook…)。你见过吗:
http://railscasts.com/episodes/235-omniauth-part-1?view=asciicast http://railscasts.com/episodes/235-omniauth-part-1?view=asciicast
http://railscasts.com/episodes/236-omniauth-part-2?view=asciicast http://railscasts.com/episodes/236-omniauth-part-2?view=asciicast
这有助于处理用户 has_many 身份,但仍然无法处理您的情况。
然后,要解决您的问题,一种选择是检测您遇到的验证错误:
if @user.errors.added?(:email, :taken)
# do whatever you want - e.g. one of the 4 options below.
end
如果发生这种情况,您可以:
-
只需将该身份添加到与具有相同电子邮件地址的现有用户关联的身份中,然后登录即可。
or
-
在将身份添加到现有用户之前,请询问现有用户帐户的密码(如果该帐户最初是通过系统上的 devise 注册的),因此您需要转到一些新的控制器/操作和视图来处理此问题流动。
or
-
也许发送一封电子邮件确认(不是设计的标准确认)以确认他们正在将其新身份链接到现有帐户。这听起来有点复杂,因为您必须将身份临时存储在某个地方(如果您想在单击确认链接之前处理他们结束当前会话的情况,则可能在数据库中),将其标记为未确认,直到他们单击确认电子邮件中的链接(您还必须处理生成)。
or
也许迫使他们使用具有相同电子邮件地址的其他身份进行身份验证。与前一个选项相比,它的优点是您可以在会话中保存新的身份信息并让它们立即使用其他服务进行身份验证,但显然需要一些工作来处理那里的流程。
选项 1 的安全性可能较低,因为您相信外部服务已确认用户的电子邮件地址(也许他们已经确认了),但您希望确保其他人可以使用其电子邮件地址注册 linkedin,然后登录您的网站并然后攻击者可以使用相同的电子邮件地址注册另一个服务。如果您未以某种方式确认他们确实拥有该电子邮件地址(例如通过使用选项 2、3 或 4),他们就可以访问您网站上的该人的帐户。如果外部服务可以确认他们已经验证了电子邮件地址,那么这个选项应该没问题,并且是迄今为止最简单的 - 例如,Facebook 有一个字段告诉您帐户已经过验证(但请参阅下面我关于服务的评论)不需要电子邮件地址)。如果他们直接与您注册的帐户合并(听起来不像您的情况),您应该使用 devise 的标准可确认功能确认他们注册的电子邮件地址。
选项 2 听起来似乎不适用于您的情况,因为您没有提到用户可以直接通过 devise 向您注册;仅使用外部服务登录。这意味着他们在您的网站上没有他们知道的密码。 (您可能添加了一个虚拟密码来让设备验证通过,除非您已禁用它,但除非您以某种方式告诉他们,否则他们不会知道密码,并且这样做可能会让他们感到困惑)。
选项 3 听起来可行,但我还没有尝试过。对于用户来说有点费力。
选项 4 听起来也可行,尽管我也没有尝试过。
到目前为止,我已经完成了选项 2,因为用户只能直接使用设备或通过 1 个外部服务在我的网站上注册。我很快就会添加其他服务,因此我计划使用选项 4(也许仅当外部服务表示尚未确认电子邮件地址时才使用,否则使用选项 1)。
选项 2、3 和 4 比选项 1 的工作量要多一些,因此这取决于您是否可以确认外部服务已验证电子邮件地址,如果没有,则取决于您对攻击者能够访问您的用户帐户的疑虑程度。地点。就我个人而言,我偏执是错误的!
这也可能为您提供一些更有用的信息:
https://github.com/intridea/omniauth/wiki/Managing-Multiple-Providers https://github.com/intridea/omniauth/wiki/Managing-Multiple-Providers
但是因为omniauth本身并不关心模型问题,所以它基本上回避了它,尽管它针对您的情况说“可能足够谨慎地假设他们实际上是创建前一个用户的同一个人”但正如我上面提到的,您必须能够信任外部服务。
还有其他需要考虑的事情,例如某人在 Facebook 上注册并链接了相同的电子邮件地址,并在您的网站上登录了这两个地址(因此,一旦您处理了您的问题,就使用单用户帐户),然后更改与其 Facebook 帐户关联但未与 linkedin 关联的电子邮件。如果您总是用外部服务中的电子邮件覆盖用户表中存储的电子邮件,那么如果他们先使用 linkedin 登录,然后使用 Facebook 登录,则电子邮件会不断变化(但这可能对您来说并不重要)。或者,他们可能在 Facebook 上注册并链接了不同的电子邮件地址,并在您的网站上登录了这两个地址(因此您的网站上有 2 个不同的用户),然后他们将链接的电子邮件地址更改为与 Facebook 相同的电子邮件地址。如果您在用户每次通过外部服务登录时更新其电子邮件地址,则会出现“电子邮件已被占用”错误,但在这种情况下,您有 2 个现有用户需要合并,这可能会很有趣,具体取决于其他内容在您的数据库中与用户关联...
另外,我认为 twitter 不会返回电子邮件地址,因此如果同一个人使用 twitter 和 linkedin 登录,您将不会检测到这一点。此外,我认为 Facebook 的电子邮件是可选的(您可以使用手机号码),因此 Facebook 也会发生同样的情况。我理想的解决方案将允许用户合并任意帐户,显然必须输入所需的任何凭据来确认他们拥有要合并的帐户!我还没有这样做,但它在我的愿望清单上!