简体   繁体   中英

skip_before_filter :authenticate_user! does not work for AJAX call

I have a 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

I send a request to session_timeout/has_user_timed_out using AJAX:

$.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();
    }
  }
});

When this AJAX call is made, I expect it to always get a response, even if the user logged out. I expect this because I set skip_before_filter :authenticate_user! in the controller. However, when I send the AJAX, the server sends back a 401 Unauthorized response. Why is this?

Moreover, when I run this JS from the browser console, it works as expected. The only time I have a problem with my AJAX is when it's called from the view.

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

One thing that could be causing the problems is that I send the AJAX request within a split-second of the user being automatically logged out due to inactivity. Would this confuse Devise at all?


EDIT: This is my Rails log when I send a request that results in a 401 response:

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

This is my Rails log when I send a request that works, even though the user is logged out:

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)

Playing around with it some more, it looks like the first time I send a request to session_timeout/has_user_timed_out after the user has been logged out, it fails, no matter how long I wait. Then, all subsequent requests succeed.

I found a workaround. $.ajax can take a status option that lets you intercept server responses based on their response codes. In my case, what I care about is whether the user is logged in. A 401 error tells me that the user is logged out, so I can intercept the response and act accordingly:

$.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'
    }
  }
});

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM