ruby-on-rails – 让Devise AJAX登录使用确认

前端之家收集整理的这篇文章主要介绍了ruby-on-rails – 让Devise AJAX登录使用确认前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
我们正在尝试扩展Devise(3.1.1)登录/注册方法来处理 AJAX请求,但是他们仍然坚持使用可确认的逻辑.通常,如果用户在确认其帐户之前登录设计,他们将被重定向登录屏幕,并显示以下消息:“您必须在继续之前确认您的帐户.”我们无法弄清楚Devise在哪里检查确认并决定重定向.

这是我们的扩展的sessions_controller代码.它适用于成功和失败的登录尝试:

# CUSTOM (Mix of actual devise controller method and ajax customization from http://natashatherobot.com/devise-rails-sign-in/):
  def create
    # (NOTE: If user is not confirmed,execution will never get this far...)
    respond_to do |format|
      format.html do 
        # Copied from original create method:
        self.resource = warden.authenticate!(auth_options)
        set_flash_message(:notice,:signed_in) if is_navigational_format?
        sign_in(resource_name,resource)
        respond_with resource,:location => after_sign_in_path_for(resource)
      end                       
      format.js  do
        # Derived from Natasha AJAX recipe:
        self.resource = warden.authenticate!(:scope => resource_name,:recall => "#{controller_path}#failure")
        sign_in(resource_name,resource)
        return render :json => {:success => true,:token => form_authenticity_token() },content_type: "application/json" # Need to explicitely set content type to JSON,otherwise it gets set as application/javascript and success handler never gets hit.
      end          
    end

  end

  def failure
    return render :json => {:success => false,:errors => ["Login Failed."]}
  end

问题是,如果用户未经确认,则create方法永远不会被命中.重定向发生在之前的某个地方,这意味着我们无法以JS友好的方式处理它.但是通过源代码我找不到任何可以进行确认检查的过滤器.确认检查在哪里发生,我们如何拦截它?

解决方法

发生的事情是sign_in方法通过抛出一个warden错误让你脱离正常流程,这将调用失败应用程序.

如果你看一下lib / devise / controllers / helpers.rb中sign_in的定义,你会发现,在你第一次登录用户的正常流程中,你最终会调用

warden.set_user(resource,options.merge!(:scope => scope)

warden是对Warden :: Proxy对象的引用,如果你看一下set_user的作用(你可以在warden/lib/warden/proxy.rb:157-182看到),你会看到在将用户序列化到会话后它会运行任何after_set_user回调.

Devise在lib / devise / hooks /中定义了一堆这些,我们感兴趣的特定的是lib / devise / hooks / activatable.rb:

Warden::Manager.after_set_user do |record,warden,options|
  if record && record.respond_to?(:active_for_authentication?) && !record.active_for_authentication?
    scope = options[:scope]
    warden.logout(scope)
    throw :warden,:scope => scope,:message => record.inactive_message
  end
end

如您所见,如果记录不是active_for_authentication?,那么我们抛出.这就是你的情况 – active_for_authentication?对于尚未确认的可确认资源,返回false(参见lib/devise/models/confirmable.rb:121-127).

当我们抛出:warden时,我们最终会调用devise failure_app.这就是正在发生的事情,以及为什么你打破了控制器的正常控制流程.

(实际上上面是谈论正常的会话控制器流程.我认为你的js块实际上是多余的 – 调用warden.authenticate!也会设置用户,所以我认为你甚至在你登录之前就扔了.)

要回答第二个问题,处理此问题的一种可能方法是创建自己的失败应用程序.默认设置将warden的failure_app设置为Devise :: Delegator,它允许您为不同的设计模型指定不同的故障应用程序,但如果没有配置任何设备,则默认为Devise :: FailureApp.您可以自定义现有的故障应用程序,通过配置warden将其替换为您自己的故障应用程序,或者您可以自定义委托者以使用html请求的默认故障应用程序并委托给json的其他故障应用程序.

原文链接:https://www.f2er.com/ruby/267479.html

猜你在找的Ruby相关文章