默认设计授权路径(即提及here的user_omniauth_authorize_path)似乎旨在用于OmniAuth注册和登录。当在OmniauthCallbacksController中收到auth时,您的rails应用程序通常使用auth信息来创建新用户或更新现有用户,无论用户是打算登录还是注册服务(即Facebook)。
我的利益相关者已经请求了auth和login的不同行为。如果用户点击"注册Facebook"并且他们的Facebook电子邮件没有帐户,他们希望继续使用该电子邮件创建帐户。但是,如果用户点击"使用Facebook登录"他们的Facebook电子邮件没有帐户,他们希望向用户显示一条错误消息,解释"您使用的Facebook帐户与我们记录中的帐户不匹配。请使用您的barre3电子邮件和密码"
登录这种逻辑的地方似乎是在OmniauthCallbacksController的Facebook方法中。将这个回调方法传递给用户的意图('登录'或注册')的最简洁方法是什么?
答案 0 :(得分:3)
您可以通过在授权网址上添加一些参数来从授权中获取参数以指示用户的意图。
例如:
- if devise_mapping.omniauthable?
- resource_class.omniauth_providers.each do |provider|
= link_to "Sign in with #{provider.to_s.titleize}", omniauth_authorize_path(resource_name, provider, {intent: :sign_in})
(这会创建一个类似于:http://whatevs.dev/users/auth/facebook?intent=sign_in)
的网址然后,在回调控制器中(无论你怎么命名):
class Users::OmniauthCallbacksController < Devise::OmniauthCallbacksController
def facebook
if env["omniauth.params"]["intent"] == "sign_in"
# Don't create a new identity
else
# Normal flow, such as:
@user = User.from_omniauth(request.env["omniauth.auth"])
sign_in_and_redirect @user
end
end
end
答案 1 :(得分:1)
如果用户点击&#34;注册Facebook&#34;并且他们的Facebook电子邮件没有帐户,他们希望继续使用该电子邮件创建帐户
此假设无效,因为Facebook只能使用电话号码创建。即使用户有电子邮件,也需要额外的许可才能从Facebook获取用户的电子邮件。 您的应用程序应验证Facebook API而不是电子邮件返回的facebook_uid。
将这个回调方法传递给用户的意图(&#39;登录&#39;或注册&#39;)的最简洁方法是什么?
对于OmniAuth,登录&#39;登录&#39;或者&#39;注册&#39;。它所做的就是尝试使用提供的Facebook令牌对用户进行身份验证。 区分的一种简洁方法是在控制器级别上进行分离。如果用户尝试登录,请调用SessionsController #create,如果用户尝试注册,请调用UsersController #create。
答案 2 :(得分:0)
我也对答案进行了过多的研究,但没有得到满意的答案,因此我向前迈了一步,并创建了可按需工作的功能。 @Jason的答案可以帮助我到达此处。
视图/用户/会话/new.html.erb
<% if devise_mapping.omniauthable? %>
<% resource_class.omniauth_providers.each do |provider| %>
<%= link_to omniauth_authorize_path(resource_name, provider, {intent: :sign_in}) do %>
<i class="fa fa-<%= provider.to_s.split('_')[0] %>"></i>
<% end %>
<% end %>
<% end %>
视图/用户/注册/new.html.erb
<% if devise_mapping.omniauthable? %>
<% resource_class.omniauth_providers.each do |provider| %>
<%= link_to omniauth_authorize_path(resource_name, provider, {intent: :sign_up}) do %>
<i class="fa fa-<%= provider.to_s.split('_')[0] %>"></i>
<% end %>
<% end %>
<% end %>
控制器/用户/omniauth_callbacks_controller.rb
class Users::OmniauthCallbacksController < Devise::OmniauthCallbacksController
def self.provides_callback_for(provider)
class_eval %Q{
def #{provider}
if request.env["omniauth.params"]["intent"] == "sign_up"
@user = User.from_omniauth_sign_up(request.env['omniauth.auth'])
elsif request.env["omniauth.params"]["intent"] == "sign_in"
@user = User.from_omniauth_sign_in(request.env['omniauth.auth'])
end
if @user.present?
sign_in_and_redirect @user, event: :authentication
set_flash_message(:notice, :success, kind: "#{provider}".capitalize) if is_navigational_format?
else
flash[:errors] = {:email => "is not registered with us."}
session["devise.#{provider}_data"] = request.env["omniauth.auth"]
redirect_to new_user_registration_url
end
end
}
end
[:google_oauth2, :facebook, :linkedin].each do |provider|
provides_callback_for provider
end
end
models / user.rb
def self.from_omniauth_sign_up(auth)
# check if email address obtained from auth server is in User table
user = User.where(email: auth[:info][:email]).first
if user.present?
user.first_name = auth.info.first_name
user.last_name = auth.info.last_name
user.image = auth.info.image
user.provider = auth.provider
user.uid = auth.uid
user.save
else
user = User.new(provider: auth.provider, uid: auth.uid)
user.email = auth.info.email
user.username = "#{auth.uid}-#{auth.provider}"
user.password = Devise.friendly_token[0,20]
user.first_name = auth.info.first_name
user.last_name = auth.info.last_name
user.image = auth.info.image
user.status_id = 2
user.skip_mobile_validation = true
user.skip_confirmation!
user.save
end
user
end
def self.from_omniauth_sign_in(auth)
if user = User.where(email: auth[:info][:email]).first
user
end
end