Devise omniauthable прерывает аутентификацию Omniauth с сообщением «Не удалось найти допустимое сопоставление для пути».

В моем проекте есть два типа пользователей: соискатели и менеджеры по найму. У соискателей нет модели, они просто могут подать заявку на работу, используя данные, полученные от сторонних поставщиков, при аутентификации через Omniauth. Информация менеджеров по найму хранится в модели пользователя. Менеджеры по найму также должны иметь возможность войти в учетную запись электронной почты Google своей компании. Итак, сначала я создал аутентификацию соискателей, используя Omniauth 1.0.0, Rails 3.1.3:

omniauth.rb

require 'omniauth-openid'
require 'openid/store/filesystem'
Rails.application.config.middleware.use OmniAuth::Builder do
   provider :openid, :store => OpenID::Store::Filesystem.new('./tmp'), :name => 'google', :identifier => 'https://www.google.com/accounts/o8/id'
   provider :facebook, "xxxxxxxxx", "xxxxxxxxxxxxxxxxxxxxxxxxxxxx",
  {:scope => 'email, offline_access, publish_stream', :client_options => {:ssl => {:ca_file => '/usr/lib/ssl/certs/ca-certificates.crt'}}}
   provider :twitter, "xxxxxxxxxxx", "xxxxxxxxxxxxxxxxxxxxxxxxxxx"
   provider :linkedin, "xxxxxxxxxxx", "xxxxxxxxxxxxxxxxxxx"
 end

in routes.rb:

match '/auth/:provider/callback', :to => 'sessions#authenticate_jobseeker'
match '/auth/failure', :to => 'sessions#failure'

in sessions_controller.rb

def authenticate_jobseeker
  session[:jobseeker] = request.env['omniauth.auth']

  if valid_job_seeker?
    redirect_to new_job_application_path(...)
  else
    redirect_to request.env['omniauth.origin'] || root_path, alert: "Authentication failure"
  end
end

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

user.rb

class User < ActiveRecord::Base
  #...
  devise :database_authenticatable, :registerable,
         ... :lockable, :omniauthable
  #...
end

in devise.rb:

config.omniauth :open_id, :store => OpenID::Store::Filesystem.new('./tmp'), :name => 'google', :identifier => 'https://www.google.com/accounts/o8/id', :require => 'omniauth-openid'

in routes.rb:

devise_for :users, :controllers => { :omniauth_callbacks => "users/omniauth_callbacks" } do
  get '/users/auth/:provider' => 'users/omniauth_callbacks#passthru'
end

В этот момент аутентификация пользователей сработала, а соискателей — нет. После некоторого поиска проблема была устранена путем добавления :path_prefix => "/auth" к каждому провайдеру в omniauth.rb. Единственная проблема сейчас, когда соискатель не разрешает доступ к своим данным (т.е. нажимает «Не разрешать» и возвращается в приложение), я получаю следующую ошибку RuntimeError для каждого провайдера:

Could not find a valid mapping for path "/auth/twitter/callback" 
Parameters:
{"denied"=>"mKjVfMRwRAN12ZxQ9cxCoD4rYSLJIRLnEqgiI"}

вершина следа:

devise (1.5.2) lib/devise/mapping.rb:48:in `find_by_path!'
devise (1.5.2) lib/devise/omniauth.rb:17:in `block in <top (required)>'
omniauth (1.0.0) lib/omniauth/strategy.rb:418:in `call'
omniauth (1.0.0) lib/omniauth/strategy.rb:418:in `fail!'
omniauth-oauth (1.0.0) lib/omniauth/strategies/oauth.rb:63:in `rescue in callback_phase'
omniauth-oauth (1.0.0) lib/omniauth/strategies/oauth.rb:45:in `callback_phase'
omniauth (1.0.0) lib/omniauth/strategy.rb:200:in `callback_call'
omniauth (1.0.0) lib/omniauth/strategy.rb:166:in `call!'
omniauth (1.0.0) lib/omniauth/strategy.rb:148:in `call'
omniauth (1.0.0) lib/omniauth/strategy.rb:168:in `call!'
omniauth (1.0.0) lib/omniauth/strategy.rb:148:in `call'
omniauth (1.0.0) lib/omniauth/strategy.rb:168:in `call!'
omniauth (1.0.0) lib/omniauth/strategy.rb:148:in `call'
omniauth (1.0.0) lib/omniauth/builder.rb:30:in `call'

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


person Simon Bagreev    schedule 20.12.2011    source источник


Ответы (2)


Отвечая на мой собственный вопрос. Итак, окончательное решение состояло в том, чтобы использовать чистую реализацию Omniauth. Я удалил :omniauthable из модели User, удалил config.omniauth... из devise.rb, удалил :omniauth_callbacks маршруты разработки из routes.rb. Таким образом, все пользователи (независимо от роли) будут использовать маршруты обратного вызова ame и нажимать действие sessions_controller#authenticate_jobseeker (следует ли подумать о переименовании действия?):

def authenticate_jobseeker
  auth_hash = request.env['omniauth.auth']

  unless auth_hash.present?
    redirect_to request.env['omniauth.origin'] || root_path, alert: "Sorry, we were not able to authenticate you" and return
  end

  @user = User.find_from_oauth(auth_hash)
  if @user.present?
    flash[:notice] = I18n.t "devise.omniauth_callbacks.success", :kind => "Google"
    sign_in_and_redirect @user, :event => :authentication and return
  else
    session[:jobseeker] = auth_hash["info"]
    if valid_job_seeker?
      redirect_to new_job_application_path(...)
    end
  end
end

и User.find_from_oauth:

def self.find_from_oauth(auth_hash)
  if auth_hash
    user = User.where(:email => auth_hash["info"]["email"]).first
  end
  user
end

Эта реализация удовлетворила всем требованиям.

person Simon Bagreev    schedule 13.01.2012

Вы где-то используете omniauth["user_info"] в своих моделях? В моем случае я обращался

omniauth["user_info"]["email"] 

и это приведет к сбою, и я получу ту же ошибку, пойманную devise.

В моем приложении мы также используем omniauth напрямую (для бизнеса), а также используем device+facebook для входа пользователей.

Однако еще не придумали, как не поймать неудачу из-за изобретения. Devise регистрирует собственное приложение сбоя. Обновлю, когда разберусь.

Обновление: извините, кажется, я неправильно понял часть вашего вопроса. Вы можете увидеть явный сбой авторизации из удаленного веб-приложения, которое, кажется, забивается, а не замаскированное исключение из кода (как было в моем случае).

person Aditya Sanghi    schedule 12.01.2012
comment
Учитывая omniauth["user_info"]["email"]. Я получил доступ к auth_hash, полученному от провайдера аутентификации, вот так request.env["omniauth.auth"]. И тут я ["info"]["email"] на нем. Хотя более новые версии devise предлагают using autn_hash.info['email']. - person Simon Bagreev; 13.01.2012