登录失败后的Devise重定向

64

我找到的所有问题都与使用辅助函数 after_sign_in_path_for(resource) 成功登录有关。

我在站点的主页(index)上有一个登录表单,当登录失败时,它会重定向到“users/sign_in”

但是当登录失败时,如何重定向到我的site#index

5个回答

102
  1. 在你的lib目录下创建一个名为custom_failure.rb的文件,其中包含:

 class CustomFailure < Devise::FailureApp
   def redirect_url
     your_path
   end

   def respond
     if http_auth?
       http_auth
     else
       redirect
     end
   end
 end
在您的Devise初始化器中,包含:
  • In your Devise initializer, include:

       config.warden do |manager|
         manager.failure_app = CustomFailure
       end
    
  • 确保Rails能够加载你的lib文件,在你的application.rb文件中:

  •  config.autoload_paths += %W(#{config.root}/lib)
    

    不要忘记重新启动你的服务器。

    我认为没有比这更容易的方法了。


    2
    这个不起作用。我知道这是从设备维基的存货答案。 - dsaronin
    respond 方法的内容可以重构为 http_auth? ? http_auth : redirect。非常好用! - RyanScottLewis
    3
    对我来说这个不起作用,它仍然会重定向回登录页面。 - Chris Edwards
    2
    这对于使用 Devise 3.2.4 的我有效。确保在包含或更改任何这些文件时,重新启动服务器。如果您没有重启,可能会出现类似以下的错误:NameError - undefined local variable or method 'login' for #<CustomFailure:0x007ffc4aeb9328> - Omni
    它对我来说有效,但仅限于一个会话。我该如何进行注册? - Code-MonKy
    2
    在Rails 5中与Devise 4.3.0完美配合。只需将custom_failure.rb文件放入/app/models/concerns中,跳过autoload_paths步骤#3即可。感谢@Marcao,你节省了我的时间! - Fernando Kosh

    15
    如果您使用自己的SessionsController,您可以重新分配auth_options中的:recall值来回调您想要运行的controller#method,然后再运行warden.authenticate!(auth_options)。例如,在app/controllers/users/sessions_controller.rb中:
    class Users::SessionsController < Devise::SessionsController
      #...
      def create
        #...
        auth_options = { :recall => 'site#index', :scope => :user }
        resource = warden.authenticate!(auth_options)
        #...
      end
      #...
    end
    
    通过这种方式,您无需创建自定义的 FailureApp 并修改配置。

    1
    这将修改URL为users/sign_in。 - Edward

    3
    这是devise 3.1.0的情况:
    Started POST "/users/sign_in"
    Processing by Devise::SessionsController#create
    Completed 401 Unauthorized
    Processing by Devise::SessionsController#new
    

    由于在gems/devise-3.1.0/app/controllers/devise/sessions_controller.rb末尾定义了auth_options,因此会调用new。

    您应该重新定义create操作中使用的auth_options。我将控制器复制到了我的Rails应用程序中的app/controllers/devise/sessions_controller.rb,并像这样替换了auth_options方法。

    def auth_options
      { :scope => resource_name, :recall => "Home#new" }
    end
    

    这个方法有效,但URL仍然是/users/sign_in。

    我也会尝试修复它。


    我现在正在使用devise 3.2.2。Marcao的解决方案完美运行,不需要复制和修补devise控制器或设置auth_options。 - pmontrasio

    1
    详细说明Marcao的答案,我强烈建议在CustomFailure响应方法中放置一些调试器,以更好地理解正在发生的事情。
    Class CustomFailure < Devise::FailureApp
      def respond
        binding.pry
        super
      end
    end
    

    如果您查看FailureApp Devise Source Code的respond方法,就会非常容易地理解正在发生的事情。
    def respond
      if http_auth?
        http_auth
      elsif warden_options[:recall]
        recall
      else
        redirect
      end
    end
    

    例如,为了返回一个重定向URL,你需要确保你的respond代码条件最终返回redirect
    但是如果你想返回一个标准的401状态,就像http_auth方法中定义的那样,你需要验证你的respond方法代码是否返回http_auth
    因此,值得一提的是,你需要查看http_auth?的定义。特别要注意的是:request.xhr?方法,它将为json请求返回0(请记住,在ruby中,0实际上等于true)。
    def http_auth?
      if request.xhr?
        Devise.http_authenticatable_on_xhr
      else
        !(request_format && is_navigational_format?)
      end
    end
    

    也许您需要检查初始化程序/设备文件中的config.http_authenticatable_on_xhrconfig.navigational_formats,以控制所需的响应。此配置确实会影响Devise返回的内容,并且由于其在底层执行的操作,通常会导致意外行为。


    1

    谢谢@MikeH,我试过了。devise_for :users do get 'users', :to => 'site#index', :as => :user_root # Rails 3 end这段代码完美地将所有情况下的重定向都指向我的索引页面,除了登录失败的情况。在这种情况下,它会重定向到"user/sign_in",而我想要重定向到"site#index"。 - Juanjo
    当登录失败时,Devise的失败应用程序会重定向到new_#{scope}_session_path(在您的情况下为new_user_session_path)。当您执行rake routes命令时,此资源路径显示哪个控制器/操作? - MikeH
    4
    你找到答案了吗?我还在寻找... - ronnieonrails

    网页内容由stack overflow 提供, 点击上面的
    可以查看英文原文,
    原文链接