我使用google_aouth2和facebook与设计。 谷歌似乎并没有与其他人合作。 这里有些例子 :
我以正常方式创建一个帐户(No omniauth) - : -我尝试使用Facebook登录,但它不会创建新帐户。 它只是登录现有帐户(电子邮件相同) - : -如果我使用Google登录,它会尝试创建新用户并提出此错误“验证失败:电子邮件已被删除”
我使用Facebook创建一个帐户- : -如果我使用Google登录,它会尝试创建一个新用户并提出此错误“验证失败:电子邮件已被删除”
我使用Google创建了一个帐户- : -我尝试使用Facebook登录,但它不会创建新帐户。 它只需登录现有帐户(电子邮件相同)
如何让谷歌像Facebook一样工作? 使用相同的电子邮件检测现有用户帐户并登录而不创建具有相同电子邮件的其他用户?
我的user.rb:
class User < ActiveRecord::Base # Include default devise modules. Others available are: # :confirmable, :lockable, :timeoutable and :omniauthable devise :database_authenticatable, :registerable, :recoverable, :rememberable, :trackable, :validatable, :confirmable, :lockable, :omniauthable VALID_EMAIL_REGEX = /\A[\w+\-.]+@[a-z\-.]+\.[a-z]+\z/i validates :email, presence: true, length: { maximum: 255 }, format: { with: VALID_EMAIL_REGEX }, uniqueness: { case_sensitive: false } def self.find_for_oauth(auth, signed_in_resource = nil) # Get the identity and user if they exist identity = Identity.find_for_oauth(auth) # If a signed_in_resource is provided it always overrides the existing user # to prevent the identity being locked with accidentally created accounts. # Note that this may leave zombie accounts (with no associated identity) which # can be cleaned up at a later date. user = signed_in_resource ? signed_in_resource : identity.user # Create the user if needed if user.nil? # Get the existing user by email if the provider gives us a verified email. # If no verified email was provided we assign a temporary email and ask the # user to verify it on the next step via UsersController.finish_signup email_is_verified = auth.info.email && (auth.info.verified || auth.info.verified_email) email = auth.info.email if email_is_verified user = User.where(:email => email).first if email # Create the user if it's a new registration if user.nil? user = User.new( #name: auth.extra.raw_info.name, username: auth.info.email, email: auth.info.email, #email ? email : "#{TEMP_EMAIL_PREFIX}-#{auth.uid}-#{auth.provider}.com", password: Devise.friendly_token[0,20], autouser: true ) if auth.provider == 'google_oauth2' user.gplus = auth.info.urls.Google end user.skip_confirmation! user.save! end end # Associate the identity with the user if needed if identity.user != user identity.user = user identity.save! end user end def email_verified? self.email && self.email !~ TEMP_EMAIL_REGEX end endIdentity.rb:
class Identity < ActiveRecord::Base belongs_to :user validates_presence_of :uid, :provider validates_uniqueness_of :uid, :scope => :provider def self.find_for_oauth(auth) find_or_create_by(uid: auth.uid, provider: auth.provider) end endomniauth_callbacks_controller.rb:
class OmniauthCallbacksController < Devise::OmniauthCallbacksController def self.provides_callback_for(provider) class_eval %Q{ def #{provider} @user = User.find_for_oauth(env["omniauth.auth"], current_user) if @user.persisted? sign_in_and_redirect @user, event: :authentication set_flash_message(:notice, :success, kind: "#{provider}".gsub(/_/," ").split[0...1].join(' ').capitalize) if is_navigational_format? else session["devise.#{provider}_data"] = env["omniauth.auth"] redirect_to new_user_registration_url end end } end [:google_oauth2, :facebook].each do |provider| provides_callback_for provider end def after_sign_in_path_for(resource) super resource end endIm using google_aouth2 and facebook with devise. Google aouth doesn't seems to play well with the others. Here are some examples :
I create an account in the normal way (No omniauth) --:-- I try to sign in with Facebook and it doesn't create a new account. It simply signin to the existing account (emails are same) --:-- If I use Google to sign in, it tries to create a new user and gives this error 'Validation failed: Email has already been taken'
I create an account using Facebook --:-- If I use Google to sign in, it tries to create a new user and gives this error 'Validation failed: Email has already been taken'
I create an account using Google --:-- I try to sign in with Facebook and it doesn't create a new account. It simply signin to the existing account (emails are same)
How can I make Google to work like Facebook? Detect the existing user account with the same email and sign in without creating another user with the same email?
My user.rb :
class User < ActiveRecord::Base # Include default devise modules. Others available are: # :confirmable, :lockable, :timeoutable and :omniauthable devise :database_authenticatable, :registerable, :recoverable, :rememberable, :trackable, :validatable, :confirmable, :lockable, :omniauthable VALID_EMAIL_REGEX = /\A[\w+\-.]+@[a-z\-.]+\.[a-z]+\z/i validates :email, presence: true, length: { maximum: 255 }, format: { with: VALID_EMAIL_REGEX }, uniqueness: { case_sensitive: false } def self.find_for_oauth(auth, signed_in_resource = nil) # Get the identity and user if they exist identity = Identity.find_for_oauth(auth) # If a signed_in_resource is provided it always overrides the existing user # to prevent the identity being locked with accidentally created accounts. # Note that this may leave zombie accounts (with no associated identity) which # can be cleaned up at a later date. user = signed_in_resource ? signed_in_resource : identity.user # Create the user if needed if user.nil? # Get the existing user by email if the provider gives us a verified email. # If no verified email was provided we assign a temporary email and ask the # user to verify it on the next step via UsersController.finish_signup email_is_verified = auth.info.email && (auth.info.verified || auth.info.verified_email) email = auth.info.email if email_is_verified user = User.where(:email => email).first if email # Create the user if it's a new registration if user.nil? user = User.new( #name: auth.extra.raw_info.name, username: auth.info.email, email: auth.info.email, #email ? email : "#{TEMP_EMAIL_PREFIX}-#{auth.uid}-#{auth.provider}.com", password: Devise.friendly_token[0,20], autouser: true ) if auth.provider == 'google_oauth2' user.gplus = auth.info.urls.Google end user.skip_confirmation! user.save! end end # Associate the identity with the user if needed if identity.user != user identity.user = user identity.save! end user end def email_verified? self.email && self.email !~ TEMP_EMAIL_REGEX end endIdentity.rb :
class Identity < ActiveRecord::Base belongs_to :user validates_presence_of :uid, :provider validates_uniqueness_of :uid, :scope => :provider def self.find_for_oauth(auth) find_or_create_by(uid: auth.uid, provider: auth.provider) end endomniauth_callbacks_controller.rb :
class OmniauthCallbacksController < Devise::OmniauthCallbacksController def self.provides_callback_for(provider) class_eval %Q{ def #{provider} @user = User.find_for_oauth(env["omniauth.auth"], current_user) if @user.persisted? sign_in_and_redirect @user, event: :authentication set_flash_message(:notice, :success, kind: "#{provider}".gsub(/_/," ").split[0...1].join(' ').capitalize) if is_navigational_format? else session["devise.#{provider}_data"] = env["omniauth.auth"] redirect_to new_user_registration_url end end } end [:google_oauth2, :facebook].each do |provider| provides_callback_for provider end def after_sign_in_path_for(resource) super resource end end最满意答案
找到答案了! 在user.rb文件中,它通过访问“auth.verified”属性来检查电子邮件是否通过Facebook验证。 如果已经过验证,它只会收取电子邮件并检查现有帐户。 问题是,Google没有提供该属性。 因此,如果有人通过Google进行身份验证,我将绕过此类验证:
if auth.provider == 'google_oauth2' email = auth.info.email else email_is_verified = auth.info.email && (auth.info.verified || auth.info.verified_email) email = auth.info.email if email_is_verified endFound the answer! In the user.rb file, it checks whether the email is verified by Facebook or not by accessing 'auth.verified' attribute. It will only take the email and check for an existing account if it's verified. The problem is,Google does not provide that attribute. So, if someone authenticate with Google I will bypass the verification like this :
if auth.provider == 'google_oauth2' email = auth.info.email else email_is_verified = auth.info.email && (auth.info.verified || auth.info.verified_email) email = auth.info.email if email_is_verified end更多推荐
发布评论