Используя 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 выдаст вам ошибку «неверный адрес электронной почты / пароль».Поиск источника был невероятно долгим процессом отладки.
Имея это в виду, я использую форму входа в систему, чтобы выполнить это действие после аутентификации пользователя.