Rails 3 и Devise: аутентификация пользователя при выполнении действия POST - PullRequest
3 голосов
/ 12 апреля 2011

Используя Rails 3.0.6, Omniauth 0.2.0 и Devise 1.2.1, я сталкиваюсь со следующей ситуацией:

Я хочу предложить пользователям возможность аутентификации через Facebook.У меня есть пользовательская система, настроенная с помощью Devise, и я могу успешно авторизоваться с помощью Facebook.Я потратил несколько часов, пытаясь кодировать поведение, которое я хочу для одной конкретной ситуации:

  • пользователь не вошел в систему
  • пользователь имеет учетную запись на сайте
  • пользовательаутентификация через Facebook

Я предлагаю пользователю 2 варианта на данный момент

  • создать учетную запись (может быть фиктивной учетной записью без предоставленной информации)
  • связать эту аутентификацию Facebook с существующей учетной записью

У меня возникли проблемы с последним вариантом.Пользователь уже прошел проверку подлинности, но мне все еще нужно, чтобы он вошел в систему со своей учетной записью на сайте.В моем AuthenticationsController есть действие, которое связывает эту аутентификацию с зарегистрированным пользователем.Однако, похоже, что Devise не дает мне возможности войти в систему, оставаясь при этом в одном действии.Это была моя первая попытка сделать это

class AuthenticationsController < ApplicationController
  before_filter :authenticate_user!, :only => :auth_link_existing_user

  ...

  def auth_link_existing_user
   ...
  end

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

Прочитав этот вопрос списка рассылки, я попытался расширить SessionsController своим собственным поведением:

def create
  resource = warden.authenticate!(:scope => resource_name, :recall => "#{controller_path}#new")
  set_flash_message(:notice, :signed_in) if is_navigational_format?
  sign_in(resource_name, resource)
  if params[:redirect]                            #new
    redirect_to params[:redirect].to_sym          #new
  else
    respond_with resource, :location => redirect_location(resource_name, resource)
  end

end

Это тоже не работает.Я определил мой auth_link_existing_user маршрут для использования глагола POST (который кажется точным), и перенаправления могут быть только GET.

Так что теперь у меня есть решение: скопируйте и вставьте код из * 1036 Devise* помощник в новой функции, которая может быть вызвана в действии контроллера без перенаправления.Мне кажется, что это не совсем идеально, потому что это дублирование кода и увеличение связи - обновление Devise или Warden, которое изменяет это поведение, также нарушит мой код.

Кто-нибудь еще пробовал что-то подобное и придумалболее элегантное решение?Видите ли вы более простой способ для меня предлагать такое или подобное поведение своим пользователям?

ОБНОВЛЕНИЕ: Для тех, кто хочет использовать мое грязное решение в конце, это то, что я сделал:

def auth_link_existing_user
  # FROM Devise/sessions/create
  resource = warden.authenticate!(:scope => :user, :recall => "registrations#auth_new")
  set_flash_message(:notice, :signed_in) if is_navigational_format?
  sign_in(:user, resource)

  # method defined in Ryan Bates' Railscast for Omniauth w/Devise
  current_user.apply_omniauth(session[:omniauth])
  current_user.save
end

обратите внимание, что это действие ДОЛЖНО быть помещено в ваш контроллер сессий.В противном случае Warden выдаст вам ошибку «неверный адрес электронной почты / пароль».Поиск источника был невероятно долгим процессом отладки.

Имея это в виду, я использую форму входа в систему, чтобы выполнить это действие после аутентификации пользователя.

1 Ответ

0 голосов
/ 09 июня 2012

Мне нравится, насколько чистое ваше решение, хотя оно углубляется в стек.

Вот как я реализовал нечто подобное, следуя примеру Facebook Devise + Omniauth на Devise wiki и изменяя метод facebook для передачи информации о сеансе в форму входа, с чем-то как это:

if @user.persisted?
    flash[:notice] = I18n.t "devise.omniauth_callbacks.success", :kind => "Facebook"
    sign_in_and_redirect @user, :event => :authentication

else
    session["devise.facebook_data"] = request.env["omniauth.auth"]
    redirect_to new_user_session_url
end

Затем, в вашем случае, я бы проверил действие контроллера входа для session["devise.facebook_data"], отправил бы токен uid + с формой и apply_omniauth, если таковой имеется.

...