![](/img/trans.png)
[英]Devise - Omniauth - Can't sign up (Email already exists) if previously logged in with provider
[英]Devise/Omniauth - How to deal with a Provider that doesn't include an email
我有一个使用Devise和Omniauth处理身份验证的Rails应用程序。 按照规定,我将在omniauth_callbacks_controller中接收来自提供程序的回调,在这里检查身份验证是否已经存在,以及是否存在使用提供程序提供的电子邮件的用户,并在必要时创建一个新用户。
我需要为每个用户提供有效的电子邮件。 我的问题来自Twitter的回调。 Twitter不为其用户提供电子邮件,因此我无法创建有效用户。 为了解决这个问题,我将提供者的数据存储在一个会话中,然后向用户发送新的注册页面,要求他们提交其电子邮件地址,以便创建一个有效的用户。 提交此表格时,我遇到了问题。 表单创建了一个新用户,但是使用该电子邮件的用户很可能已经存在(在这种情况下,我需要向该用户添加身份验证)。
目前,我正在检查是否存在与新用户使用相同电子邮件的用户。 如果是这样,我将忽略新用户,并将身份验证应用于已经存在的用户。 但是,这感觉确实很hack。
我应该怎么做?
class Users::RegistrationsController < Devise::RegistrationsController
def build_resource(*args)
super
if session[:omniauth]
#If a user with this email already exists then use them instead
existing_user = User.find_by_email(@user.email)
if(existing_user)
existing_user.email = @user.email
@user = existing_user
end
#If there is a session available, we know it contains data for adding an authentication
@user.apply_omniauth_data_as_authentication(session[:omniauth])
#Ensure validations are passed on to next page
@user.valid?
end
end
干得好。 我会尝试并记住从哪里获得修复程序,如果这样做的话,会发布一个链接:
class Users::OmniauthCallbacksController < Devise::OmniauthCallbacksController
# This controller handles callbacks from Omniauth providers. If a user already exists with this provider we sign them in.
# Otherwise we either add an authentication to the current user, or create a new user if one doesn't exist.
def facebook
authorize
end
def twitter
authorize
end
private
def authorize
omniauth_data = request.env["omniauth.auth"]
#Check to see if we have an authentication for this provider already stored for any User
authentication = Authentication.find_by_provider_and_uid(omniauth_data['provider'], omniauth_data['uid'])
#If an authentication already exists, sign the owning User in
if authentication
flash[:notice] = "Signed in successfully with " + omniauth_data['provider'].titleize
sign_in_and_redirect(:user, authentication.user)
#Otherwise if there is a current User, add a new authentication for them
elsif current_user
current_user.authentications.create(:provider => omniauth_data['provider'], :uid => omniauth_data['uid'], :token => omniauth_data['token'])
flash[:notice] = "Authentication successful"
redirect_to user_profile_url
#Otherwise we check if a user exists with the email address provided by the provider (if provided at all))
else
email = omniauth_data['info']['email']
user = User.find_by_email(email)
#If no user exists, create a new one
if(!email || !user)
user = User.new
end
user.apply_omniauth_data_as_authentication(omniauth_data)
#If they save successfully (meaning we have enough data from the authorisation) sign them in
if user.email?
#We got all we needed from the provider so we don't need them to confirm'
user.skip_confirmation!
user.save!
flash[:notice] = "Signed in successfully with " + omniauth_data['provider']
sign_in_and_redirect(:user, user)
#Otherwise we need to have the visitor manually submit missing information
else
#save the omniauth data in a session so we can add the authentication once registration is complete
flash[:alert] = "Please complete registration"
session[:omniauth] = omniauth_data.except('extra')
redirect_to new_user_registration_url
end
end
end
end
我喜欢此链接使用的解决方案http://www.orhancanceylan.com/rails-twitter-and-facebook-authentications-with-omniauth-and-devise/
它使用提供者凭据在正常的设计过程中注册(以及在用户或单独的表上填写提供者和uid属性)。 因此,当新用户尝试使用提供者进行注册时,将要求他们输入电子邮件和密码,从而减少麻烦(例如希望以常规方式登录,但没有密码可输入,然后您必须处理该问题)。
尽管此解决方案在第一时间就抵消了在社交媒体上注册的便利性,但它却以最小的努力创造了长期的有益效果。
如果您绝对不希望这种要求,以免丢失注册信息或网站看起来不够美观,请找到另一种解决方案,并尽一切努力来处理这些下游案件。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.