我认为您将omniauth 与devise 分开配置(在omniauth 初始化程序中),但仍然使用devise 进行登录(为omniauth 设计路径)。
我留下了让它与设计工作流程一起工作的步骤
宝石文件
gem 'devise'
gem 'omniauth-facebook'
config/initializers/devise.rb
//add this for tell devise the omniauth configuration for facebook
config.omniauth :facebook, ENV['FACEBOOK_APP_ID'], ENV['FACEBOOK_SECRET']
config/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,我们将通过provider 和他的uid 来识别我们的用户( user 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 在我们的用户模型
中处理的方法
models/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 将使用哈希中的omniauth 参数创建一个新用户(您可以在omniauth facebook gem 中查看facebook 的omniauth 哈希),在这里你应该保存另一个值,比如 image_link 或 username 如果你有你的用户模型,我想从这里调用另一个模型 user_profile 与所有这些数据试图留下他自己的东西。
接下来我们有一个新的会话,它使用我们保存的 cookie 的内容,以防我们的回调发生错误
password_required? 和 update_with_password 都是我们需要重写的设计方法,这个方法抓住了我们在具有omniauth 提供程序且未定义密码的情况下的新行为,您可以在您的表单中使用 has_no_password? 以在需要时显示密码字段(在没有密码的情况下更新用户属性)。
我希望它有所帮助,当您了解工作流程非常容易自定义行为时,但遗憾的是大多数指南只允许您复制粘贴代码。