2012-03-14 11 views
9

considerar esta vista de Django que obtendrá una lista de elementos asociados al usuario actual:¿Cuál es la mejor manera de manejar los tiempos de espera de sesión en las solicitudes de AJAX?

@login_required 
def list_items(request, page_number=0): 
    items = Paginator(request.user.items, 5).page(page_number).object_list 
    return HttpResponse(cjson.encode(items)) 

Obviamente, quiere usar el decorador login_required, para restringir el acceso a la vista para los usuarios registrados.

¿Qué hace login_required cuando un usuario no autenticado intenta acceder a la vista? Devuelve HttpResponseRedirect hacia settings.LOGIN_URL.

consideran este código JavaScript, que llama a la vista:

var getPage = function(pageNumber) { 
    $.ajax({ 
     url: "/list_items/" + pageNumber + "/", 
     success: function(data) { 
      $("#list_container").html(formatData(data)) 
     } 
    }); 
}; 

Supongamos settings.SESSION_COOKIE_AGE = 60 segundos.

Si un usuario va a la página 1, lo lee durante 61 segundos, luego hace clic en el botón de la página 2, login_required decorador de Django detectará que la sesión ya no está activa, y devolverá un HttpResponseRedirect(settings.LOGIN_URL), lo que hará que la success devolución de llamada para obtener una página de inicio de sesión HTML en lugar de la lista codificada JSON.

This is where it happens.
It's called by user_passes_test here.

Cuál es la mejor manera de manejar esto?

Aquí hay algunas cosas que he pensado:

1. La devolución de llamada success debe comprobar la respuesta, y ver si se pone una página de inicio de sesión, por cualquier medio (comprobar si el tipo de contenido es HTML, comprobar el contenido , etc.) Pero esto significa que tenemos para envolver toda llamadas AJAX con un envoltorio de devolución de llamada de esta manera:

$.ajax({ 
     url: "/list_items/" + pageNumber + "/", 
     success: sessionExpiryCallbackWrapper(function(data) { 
      $("#list_container").html(formatData(data)) 
     }) 
    }); 

pero esto es feo, y los desarrolladores podría olvidarse de hacer esto en todas partes.

2. Use $.ajaxComplete para manejar todas las solicitudes.

$.ajaxComplete(globalCompleteCallback); 
    $.ajax({ 
     success: successCallback, 
     complete: completeCallback 
    }); 

Pero este es el orden de llamada:

successCallback(); // success is called before complete 
    completeCallback(); 
    globalCompleteCallback(); // this is called after the local callback 

Tan solo nos queda coger el redireccionamiento, después successCallback ha fallado, y posiblemente con errores JS debido a los datos no válidos que recibió.

3. Si login_required volvería en 403 peticiones AJAX:

if not user.is_authenticated(): 
     if request.is_ajax(): 
      # send 403 to ajax calls 
      return HttpResponse403("you are not logged in") 
     else: 
      # regular code path 
      return HttpResponseRedirect(settings.LOGIN_URL) 

Pero login_required simplemente utiliza user_passes_test que no hace esto.

user_passes_test tiene mucha funcionalidad, por lo que no es una buena idea volver a implementarla.

¿Cuál es la mejor manera de manejar los tiempos de espera para las llamadas AJAX?

+1

Lo siento, pero voy a poner todo en ti filosófico. La intención original de los tiempos de espera de la sesión era evitar que el servidor retuviera recursos significativos o tener que realizar costosas operaciones en cada solicitud. Ahora tenemos frameworks del lado del cliente haciendo la mayor parte del trabajo. Entonces, ¿por qué se necesitan tiempos de espera de sesión cortos? –

+0

@DaveMethvin Los tiempos de espera de sesión son necesarios para reducir la ventana para el secuestro de la sesión, ya sea a) en el cable/aire o b) físicamente por alguien que va a la computadora de otra persona después de haber AFK un poco. – Prody

+1

Ese problema parece bastante fácil de resolver, solo que los tiempos de espera de la sesión del cliente sean más cortos que los del servidor. Si ese es el caso, es muy raro que el cliente haga alguna vez una solicitud que se encuentre en un servidor sin una sesión válida. Además, eso significa que puedes mostrar un mensaje interesante, iniciado por el cliente, "tu sesión ha expirado". –

Respuesta

5

Lo manejaría haciendo que el método de tiempo de espera de la sesión compruebe si se está solicitando o no con AJAX. Si es ajax, devuelve un código de estado 401 no autorizado (o 403 prohibido o lo que sea que tenga sentido) con una cadena json vacía. A continuación, en su javascript, enlace un controlador global ajaxError que verifica ese código de estado y lo maneja de forma adecuada.

+1

Esto es lo que finalmente hice, pero tuve que escribir un nuevo decorador 'login_required' para' devolver HttpResponse40 {1,3} if request.is_ajax() else RedirectToLoginPage() 'en lugar de simplemente redirigir de cualquier manera. – Prody

0

Puede usar algo como http://amplifyjs.com/ que le permite escribir un buen envoltorio para sus llamadas AJAX y luego usar su característica data mapping para verificar si el usuario aún está conectado antes de hacer la llamada AJAX.

De esta manera puede tener un temporizador del lado del cliente que establece el estado de usuario desconectado y proporciona una pista para que la verificación de inicio de sesión no sea necesaria antes de cada llamada AJAX.

Como alternativa, puede usar un decoder personalizado que le pide al usuario que inicie sesión y vuelva a intentar la llamada AJAX si el usuario ha cerrado la sesión. Necesitaría almacenar todos los datos xhr y las devoluciones de llamadas con las que recibe llamadas hasta que el usuario inicie sesión.

Cuestiones relacionadas