Omniauth не отвечает на запрос GET

Я пытаюсь включить пользователей с возможностью входа через Facebook.

Моя аутентификация управляется Devise, и я использую гем Omniauth-Facebook.

Когда я пытаюсь войти в систему через Facebook в моих разработках (session/new.html.erb), пользователь успешно вошел в систему.

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?

1 ответ

Решение

Я думаю, вы настраиваете omniauth отдельно от devise(в инициализаторах omniauth), но все еще используете devise для входа в систему (пути разработки для 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']

конфиг / окружающие среды / 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, мы получаем этот хэш request.env["omniauth.auth"] со всеми параметрами omniauth, и теперь нам нужно определить наш метод 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 создаст нового пользователя с параметрами omniauth из хэша (вы можете увидеть хэш omniauth для facebook в геме omniauth facebook), здесь вы должны сохранить другие значения, такие как image_link или username, если у вас есть ваш пользовательская модель, мне нравится вызывать другую модель user_profile со всеми этими данными, пытаясь придумать свои собственные вещи.

Затем у нас есть новое с сеансом, который использует содержимое куки, которую мы сохраняем в случае ошибки в нашем обратном вызове

Требуется пароль? и update_with_password - оба метода devise, которые нам нужно переопределить, этот захватит наше новое поведение для случаев с провайдером omniauth и без определения пароля, вы можете использовать has_no_password? в ваших формах для отображения полей пароля именно тогда, когда это необходимо (обновить атрибуты пользователя без пароля).

Я надеюсь, что это поможет, когда вы поймете, что рабочий процесс действительно легко настроить, но, к сожалению, большинство руководств просто позволяют копировать и вставлять код.

Другие вопросы по тегам