javascript - skip_before_filter :authenticate_user! 不适用于 AJAX 调用

标签 javascript ruby-on-rails ajax devise ruby-on-rails-4

我有一个 Controller :

class SessionTimeoutController < ApplicationController
  # snip

  skip_before_filter :authenticate_user!, only: [:has_user_timed_out]

  #snip

  # Determines whether the user has been logged out due to
  # inactivity or not.
  def has_user_timed_out
    @has_timed_out = (!user_signed_in?) or (current_user.timedout? (user_session["last_request_at"]))

    respond_to do |format|
      format.json { render json: @has_timed_out, status: :created}
    end
  end

  #snip
end

我使用 AJAX 向 session_timeout/has_user_timed_out 发送请求:

$.ajax({
  url: '/session_timeout/has_user_timed_out',
  type: 'GET',
  dataType: 'json',
  success: function( logged_out ) {
    if(logged_out === true)
    {
      window.location = '/users/sign_in?timedout=1'
    }
    else
    {
      checkTimeLeft();
    }
  }
});

当进行这个 AJAX 调用时,我希望它总是能得到响应,即使用户已注销。我预计这是因为我在 Controller 中设置了 skip_before_filter :authenticate_user!。但是,当我发送 AJAX 时,服务器发回 401 Unauthorized 响应。这是为什么?

此外,当我从浏览器控制台运行此 JS 时,它按预期工作。我的 AJAX 唯一有问题的时候是从 View 中调用它的时候。

$.ajax({url: '/session_timeout/has_user_timed_out', type: 'GET', dataType:'JSON', success: function(logged_out) {console.log(logged_out + ' ' + typeof logged_out);}});

可能导致问题的一件事是我在用户由于不活动而自动注销的瞬间发送 AJAX 请求。这会让 Devise 感到困惑吗?


编辑:当我发送导致 401 响应的请求时,这是我的 Rails 日志:

Started GET "/session_timeout/has_user_timed_out" for 10.0.2.2 at 2013-07-25 21:25:51 +0000
Processing by SessionTimeoutController#has_user_timed_out as JSON
  ConfigVar Load (0.2ms)  SELECT `config_vars`.* FROM `config_vars` WHERE `config_vars`.`name` = 'maintenance_mode' ORDER BY `config_vars`.`id` ASC LIMIT 1
  User Load (0.3ms)  SELECT `users`.* FROM `users` WHERE `users`.`id` = 14 ORDER BY `users`.`id` ASC LIMIT 1
Completed 401 Unauthorized in 4ms

这是我发送有效请求时的 Rails 日志,即使用户已注销也是如此:

Started GET "/session_timeout/has_user_timed_out" for 10.0.2.2 at 2013-07-25 21:29:39 +0000
Processing by SessionTimeoutController#has_user_timed_out as JSON
  ConfigVar Load (0.1ms)  SELECT `config_vars`.* FROM `config_vars` WHERE `config_vars`.`name` = 'maintenance_mode' ORDER BY `config_vars`.`id` ASC LIMIT 1
Completed 201 Created in 3ms (Views: 0.1ms | ActiveRecord: 0.1ms)

再试一试,看起来我第一次在用户注销后向 session_timeout/has_user_timed_out 发送请求,无论我等待多长时间,它都会失败。然后,所有后续请求都会成功。

最佳答案

我找到了解决方法。 $.ajax 可以采用 status 选项,让您可以根据响应代码拦截服务器响应。就我而言,我关心的是用户是否登录。401 错误告诉我用户已注销,因此我可以拦截响应并采取相应措施:

$.ajax({
  url: '/session_timeout/has_user_timed_out',
  type: 'GET',
  dataType: 'json',
  success: function( logged_out ) {
    if(logged_out === true)
    {
      window.location = '/users/timedout'
    }
    else
    {
      checkTimeLeft();
    }
  },
  // THIS IS THE CODE I ADDED FOR MY WORKAROUND:
  statusCode: {
    // If we get back an authentication error, it's a
    // pretty safe bet we're not logged in anymore
    401: function() {
      window.location = '/users/timedout'
    }
  }
});

关于javascript - skip_before_filter :authenticate_user! 不适用于 AJAX 调用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17868721/

相关文章:

javascript - 多文件 backbone.js 应用程序似乎不起作用

ruby-on-rails - 如何在 Rails 中建模 "can belong to A or B"关系?

javascript - 将 javascript 变量传递给 AJAX 成功函数

asp.net - UpdatePanel 有时会刷新整个页面

javascript - 停止输入键单击按钮

javascript - NodeJS 服务器从 MongoDB 返回空数据

ruby-on-rails - 指定 gem 版本还是始终使用最新版本?

ruby-on-rails - 源表别名

php - 我可以让实时 PHP 数据显示在 jquery 对话框中吗?

javascript - 我如何在点击图片时播放 vimeo 播放器?