2014-02-09 61 views
3

我想创建一个轨道4应用程序与omniauth色器件:omniauth-色器件的错误:“验证失败:电子邮件已经采取”

  • 登入与Facebook
  • 签到随着谷歌
  • 登入与LinkedIn
  • 登入与Twitter

在这里,我能够与任何的Facebook,LinkedIn,Twitter或谷歌帐户登录英寸但我的问题是:我的谷歌帐户电子邮件和linkedin电子邮件地址是一样的。并与谷歌的首页,然后用LinkedIn是给我这个错误登录:

"Validation failed: Email has already been taken"

这是一个问题,因为在色器件迁移文件使用:unique => true电子邮件领域。

谁能给我提供很好的想法来处理这个错误吗?

+0

如果OAuth的帐户(谷歌,LinkedIn,Facebook的)已经被验证,那么你可以简单地连结帐户。你在哪里定义'provider'和'uid'字段?它们是“用户”表的一部分,还是您创建了一个单独的“认证”表? – Ashitaka

+0

我已经在''''User'''表中定义了''''''''''''''''''''''''。我没有为它创建单独的Authentications表。 – przbadu

+0

就像@Ashitaka建议的那样,你可以维护一个单独的认证表,所以它是用户与认证之间的1对M关系。 – omarvelous

回答

0

我跟着我这些步骤,做工精细:

1的Gemfile

gem 'omniauth-facebook', '1.4.0' 
gem 'omniauth-twitter' 
gem 'omniauth-google-oauth2' 

2.配置/ route.rb

devise_for :users, controllers: { omniauth_callbacks: "omniauth_callbacks" } 

3.链接

<%= link_to "Sign in with Facebook", user_omniauth_authorize_path(:facebook) %> 
<%= link_to "Sign in with twitter", user_omniauth_authorize_path(:twitter) %> 
<%= link_to "Sign in with google", user_omniauth_authorize_path(:google_oauth2) %> 

4.控制器/ omniauth_callbacks_controller.rb

class OmniauthCallbacksController < Devise::OmniauthCallbacksController 
    skip_before_filter :authenticate_user! 

    def all 
    user = User.from_omniauth(request.env["omniauth.auth"], current_user) 
    if user.persisted? 
      flash[:notice] = "you are successfully logged in!!" 
      sign_in_and_redirect(user) 
     else 
      session["devise.user_attributes"] = user.attributes 
      redirect_to new_user_registration_url 
     end 
    end 

    def failure 
    super 
    end 

    alias_method :facebook, :all 
    alias_method :twitter, :all 
    alias_method :google_oauth2, :all 
end 

5.添加必需字段和模型

rails g migration add_social_network_info_columns_to_users name image_url locations 

# generate new model Authorization 
rails g model Authorization user_id:integer provider uid token secret username 

6.模型/ User.rb

class User < ActiveRecord::Base 


require 'securerandom' 

    # Include default devise modules. Others available are: 
    # :confirmable, :lockable, :timeoutable and :omniauthable 
    devise :database_authenticatable, :registerable, 
    :recoverable, :rememberable, :trackable, :validatable, 
    :omniauthable 

    has_many :authorizations 

    # omniauth facebook provider 
    def self.from_omniauth(auth, current_user) 
    # check for existing authorization 
    # Find or create Authorization with: provider, uid, token and secret 
    authorization = Authorization.where(
     :provider => auth.provider, 
     :uid => auth.uid.to_s, 
     :token => auth.credentials.token, 
     :secret => auth.credentials.secret 
    ).first_or_initialize 

    if authorization.user.blank? 
     user = current_user.nil? ? User.where('email = ?', auth["info"]["email"]).first : current_user 

     # save user related data in user table 
     if user.blank? 
     User.new(
      :email   => auth.info.email, 
      :password   => Devise.friendly_token[0,10], 
      :name    => auth.info.name, 
      :locations  => auth.info.location, 
      :image_url  => auth.info.image 
     ) 
     # since twitter don't provide email, 
     # so you need to skip validation for twitter. 
     auth.provider == "twitter" ? user.save!(:validate => false) : user.save! 
     end 

     # store authorization related data in authorization table 
     authorization.username = auth.info.nickname 
     authorization.user_id = user.id 
     authorization.save! 
    end 
    authorization.user 
    end 
end 

6.模型/授权。RB

class Authorization < ActiveRecord::Base 
    belongs_to :user 
end 

source: https://github.com/mohitjain/social-login-in-rails

3

我认为,基本上,如果妥善处理所有的情况下,这可以除非你选择下面的选项1是非常复杂的(即使如此,也有考虑,我后来概括的问题)。对不起,这个答案的长度!

我假设你已经做了这样的事情:

https://github.com/plataformatec/devise/wiki/OmniAuth:-Overview

到目前为止,它让你一些方法,但不处理你遇到的问题。

我这样做的方式,我有谁HAS_MANY身份的用户。 Identity存储外部服务的名称,它告诉您的用户标识以及您想要的任何其他内容。这意味着相同的用户可以使用多个身份(Twitter,Facebook ...)登录。你见过:

http://railscasts.com/episodes/235-omniauth-part-1?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 

,如果发生了,你既可以:

  1. 只需添加身份与具有相同电子邮件地址的现有用户相关联的身份,然后对其进行签名。

  2. 添加身份现有用户之前,要求输入密码为现有用户帐户(如果该帐户是通过色器件最初注册您的系统上),所以你需要去一些新的控制器/动作和视图处理这个流程。

  3. 也许发送电子邮件确认(不是设计的标准确认)承认,他们正在将他们的新身份现有帐户。这听起来有点复杂,因为你必须暂时在某处存储身份(如果你想在点击确认链接前结束当前会话,可能在数据库中),将其标记为未确认,直到他们点击确认链接在一个电子邮件(你也必须处理生成)。

  4. 也许迫使它们与具有相同的电子邮件地址对方的身份进行认证。与前面的选项相比,您可以将新的身份信息保存在会话中,并让他们立即使用其他服务进行身份验证,但显然会有一些工作来处理那里的流程。

选项1可不太安全,因为你相信外部服务确认用户的电子邮件地址 - 这也许是他们 - 但你要确保,否则有人会使用他们的电子邮件地址注册了LinkedIn和然后登录您的网站,然后攻击者可以使用其他服务注册,但使用相同的电子邮件地址。如果您没有确认他们真的拥有电子邮件地址(例如使用选项2,3或4),他们就可以访问您网站上该用户的帐户。如果外部服务可以确认他们已经验证了电子邮件地址,那么这个选项应该没问题,并且是迄今最简单的 - 例如,Facebook有一个字段告诉您该帐户已被验证(但请参阅以下有关服务的评论不需要电子邮件地址)。如果他们正在与直接注册的账户合并(听起来不像您的情况),您应该确认使用设备的标准Confirmable功能注册的电子邮件地址。

选项2听起来像它不适用于您的情况,因为您没有提到用户可以通过设计直接向您注册;只能使用外部服务登录。这意味着他们在您的网站上没有他们知道的密码。 (你可能已经添加了一个虚拟的来让设计验证通过,除非你已经禁用了它,但是除非你以某种方式告诉它们,否则他们不会知道密码,并且它们可能会让他们感到困惑。 )。

选项3听起来可以,尽管我还没有尝试过。这对用户来说有点麻烦。

选项4也听起来可以,尽管我还没有尝试过。

到目前为止,我已经做了选项2,因为用户只能通过设备或通过1个外部服务注册我的网站。我将很快添加其他服务,因此我打算使用选项4(可能仅当外部服务说他们没有确认电子邮件地址,否则选项1)。

选项2,3和4的选择比选项1多一点,所以它取决于您是否可以确认外部服务已经验证了电子邮件地址,如果没有,您是多么偏执于攻击者能够访问用户帐户在您的网站上。就我个人而言,我偏偏偏执狂!

这也可能会给你一些有用的信息:

https://github.com/intridea/omniauth/wiki/Managing-Multiple-Providers

但由于omniauth本身不与模型问题涉及自身,它主要是回避它,虽然它说了你的情况,这是“可能是足够谨慎的,以为他们实际上是同一个人也创造了以前的用户”,但是你必须能够像上面提到的那样信任外部服务。

还有其他一些事情需要考虑,例如某人在Facebook上注册了相同的电子邮件地址并已链接并已在您的网站上同时登录(因此,一旦您处理了您的个人用户帐户问题),然后更改与他们的Facebook帐户相关的电子邮件,但不是linkedin。如果你总是用外部服务中的用户表覆盖存储在用户表中的电子邮件,那么如果他们使用LinkedIn和Facebook登录(但也许这对你无关紧要),它将不断变化。或者,他们可能会在Facebook上注册不同的电子邮件地址,并且已经在您的网站上链接并登录了两个电子邮件地址(因此您的网站上有两个不同的用户),然后他们将其链接的电子邮件地址更改为与Facebook相同。如果您每次通过外部服务登录时更新用户的电子邮件地址,则会出现“已发送电子邮件”错误,但在这种情况下,您有2个现有用户进行合并,这可能很有趣,具体取决于还有哪些其他用户在你的数据库与用户相关...

此外,我不认为微博返回一个电子邮件地址,所以如果同一个人已经与twitter和linkedin登录,你不会检测到这一点。此外,我认为Facebook的电子邮件是可选的(您可以使用手机号码),所以Facebook也可能会发生同样的情况。我的理想解决方案将允许用户合并任意账户,显然必须输入所需的任何凭证以确认他们拥有正在合并的账户!我还没有这样做,但它在我的愿望清单上!

相关问题