Deviseomniauthable 因“无法找到有效的路径映射”而破坏了 Omniauth 身份验证

发布于 12-22 14:51 字数 3510 浏览 3 评论 0原文

在我的项目中,我有两种类型的用户:求职者和招聘经理。求职者没有模型,他们只能使用从第三方提供商收到的数据来申请工作,同时通过 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< /code>

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 中的每个提供者。 现在唯一的问题是,当求职者不允许访问其数据时(即按“不允许”并返回到应用程序),我会为每个提供商提供以下运行时错误:

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'

我一直在现在正在尝试解决它一段时间。非常感谢任何帮助。如果我可以提供更多信息,请告诉我。

In my project, I have two type of users: job seekers and hiring managers. Job seekers don't have a model, they are just able to apply for jobs using the data received from from third-party providers while authenticating thru Omniauth. Hiring managers' info is stored in devise User model. Hiring managers also must be able to sign in with their company's Google email account.
So, first I built job seekers' authentication using 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

Up to this point everything worked fine. However, when I started implementing Google sign on for User model, and added :omniauthable to it, my job seeker authentication broke. I am using 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

At this point, Users' authentication worked, but job seekers' did not. After searching for a while, the issue was fixed by adding :path_prefix => "/auth" to every provider in omniauth.rb.
The only problem now, is when job seeker does not allow access to its data (i.e. presses "Don't Allow" and comes back to the application), I get following RuntimeError for every provider:

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

top of the trace:

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'

I've been trying to solve it for a while now. Any help is greatly appreciated. Let me know, if I can provide additional info.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

眼眸里的快感2024-12-29 14:51:37

回答我自己的问题。因此,最终决定采用纯粹的 Omniauth 实施。我从 User 模型中删除了 :omniauthable,从 devise.rb 中删除了 config.omniauth...,删除了 < code>:omniauth_callbacks 从 routes.rb 设计路由。
,所有用户(无论什么角色)都将使用相同的回调路由并点击 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

因此 实施满足了所有要求。

Answering my own question. So, final decision was to go with pure Omniauth implementation. I removed :omniauthable from User model, removed config.omniauth... from devise.rb, removed :omniauth_callbacks devise routes from routes.rb.
So, all users (no matter what role) would use ame callback routes and hit sessions_controller#authenticate_jobseeker action (should consider renaming the action?):

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

and 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

This implementation satisfied all of the requirements.

叫嚣ゝ2024-12-29 14:51:37

您是否在模型中的某处使用omniauth[“user_info”]?就我而言,我正在访问

omniauth["user_info"]["email"] 

,这会崩溃,我会得到同样的错误,被设备捕获。

在我的应用程序中,我们直接使用omniauth(对于企业)以及使用device+facebook 进行用户登录。

不过,还没有弄清楚如何避免失败。 Devise 注册了自己的失败应用程序。当我弄清楚时会更新。

更新:很抱歉,我似乎误读了您问题的部分内容。您可以看到远程 Web 应用程序授权明显失败,这似乎是堵塞的,而不是代码中的屏蔽异常(就像我的情况一样)。

Are you using omniauth["user_info"] in your models somewhere? In my case, I was accessing

omniauth["user_info"]["email"] 

and that would crash and I would get the same error, being caught by devise.

In my app as well, we use omniauth directly (for businesses) as well as use device+facebook for user logins.

Havent yet figured out to not get failure caught by devise though. Devise registers it's own failure app. Will update when i figure it out.

Update: I'm sorry it seems I misread part of your question. You can see a clear failure to authorize from the remote webapp which seems to stuff up and not a masked exception from the code (as was in my case).

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文