我正在尝试为用户提供通过Facebook登录的选项。
我的身份验证由Devise管理,我正在使用Omniauth-Facebook gem。
当我尝试在我的设计视图(session / new.html.erb)中通过Facebook登录用户时,用户已成功登录。
new.html.erb
<div><%= link_to image_tag('facebook_login.png'), user_omniauth_authorize_path(:facebook) %></div>
然而,当我尝试在不同的控制器中登录用户时(使用与上面完全相同的代码),该页面并没有真正响应,我在日志中遇到以下请求:
Started GET "/users/auth/facebook" for 127.0.0.1 at 2014-06-07 21:14:41 -0300
I, [2014-06-07T21:14:41.311370 #4592] INFO -- omniauth: (facebook) Request phase initiated.
Devise是否仅允许用户通过单个控制器登录facebook,还是需要对link_to路径进行其他更改?
答案 0 :(得分:2)
我认为你将omniauth与devise(在omniauth初始化器中)分开配置,但仍然使用devise for login(设计omniauth的路径)。
我留下了让它与设计工作流程一起工作的步骤
<强>的Gemfile 强>
gem 'devise'
gem 'omniauth-facebook'
<强>配置/初始化/ devise.rb 强>
//add this for tell devise the omniauth configuration for facebook
config.omniauth :facebook, ENV['FACEBOOK_APP_ID'], ENV['FACEBOOK_SECRET']
<强>配置/ enviroments / development.rb 强>
//your secrets for development, is useful have it this way because you can use different applications for your rails enviroments
ENV['FACEBOOK_APP_ID'] = 'xxxxxxxxxxx';
ENV['FACEBOOK_SECRET'] = 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx';
<强>的routes.rb 强>
//override the controller for omniauth callbacks, we will define this later, this is our custom behavior for dealing with what omniauth hash will return to us
devise_for :users, controllers: { omniauth_callbacks: "users/omniauth_callbacks" }
好的,这是基本的,现在我们需要自定义回调来定义如何处理facebook给我们的信息。
我没有这方面的工作示例,我的回调实际上非常复杂,因为有很多行为,但我会尝试通过内存来解释。
Facebook和所有omniauth策略将返回 uid ,我们将通过提供商和他的 uid 识别我们的用户(用户ID),所以我们要将这个参数添加到我们的用户模型并执行相应的迁移,这些都是字符串。
rails g migration AddOmniauthToUsers uid provider
rake db:migrate
下一步是配置我们的omniauth回调
controllers / users / omniauth_callbacks_controller.rb (请注意,它位于新用户文件夹中)
class Users::OmniauthCallbacksController < Devise::OmniauthCallbacksController
//this inheritance from Devise::OmniauthCallbacks so we will have all his methods
#uncomment the next line to see the hash from facebook, utile for debugging to see if we are getting a connection to facebook or not.
#raise request.env["omniauth.auth"].to_yaml
def all
user = User.from_omniauth(request.env["omniauth.auth"])
if @user.persisted?
sign_in_and_redirect @user, :event => :authentication #this will throw if @user is not activated
flash[:notice] = I18n.t "devise.omniauth_callbacks.success", :kind => user.provider.titleize
else
session["devise.user_attributes"] = request.env["omniauth.auth"] #create a cookie with omniauth hash to give it another try, for example in a already register email
redirect_to new_user_registration_url
end
end
//alias method is for have the same method for various strategies(google, twitter, etc)
alias_method :facebook, :all
end
基本上,当我们点击facebook连接时,我们得到所有omniauth参数的哈希 request.env [“omniauth.auth”] ,现在我们需要定义 from_omniauth 用于处理用户模型
的方法<强>模型/ user.rb 强>
def self.from_omniauth(auth)
where(auth.slice(:provider, :uid)).first_or_create do |user|
user.provider = auth.provider
user.uid = auth.uid
user.email = auth.info.email
end
end
def self.new_with_session(params, session)
if session["devise.user_attributes"]
new(session["devise.user_attributes"], without_protection: true) do |user|
user.attributes = params
user.valid?
end
else
super
end
end
def password_required?
super && self.provider.blank?
end
def update_with_password(params, *options)
if encrypted_password.blank?
update_attributes(params, *options)
else
super
end
end
def has_no_password?
self.encrypted_password.blank?
end
这里我们有4个新方法, from_omniauth 将使用hash 中的omniauth参数创建一个新用户(你可以在omniauth facebook gem中看到facebook的omniauth哈希),在这里你应该保存另一个值,如image_link或username,如果你有你的用户模型,我想从这里调用另一个模型user_profile,所有这些数据都试图让他自己的东西设置。
接下来我们有一个新的会话,它使用我们保存的cookie的内容,以防我们的回调出错
password_required?和 update_with_password 都是我们需要覆盖的设计方法,这个方法使用omniauth提供程序获取我们的新行为并且没有定义密码,你可以在表单中使用 has_no_password?,以便在需要时显示密码字段(更新没有密码的用户属性)。
我希望它有所帮助,当你理解工作流程很容易定制行为时,但遗憾的是大多数指南只是让你复制粘贴代码。