Es posible enviar un 401 no autorizado Y redirigir (con una Ubicación)?


Me gustaría enviar un 401 Unauthorized Y redirigir el cliente a alguna parte. Sin embargo:

Si lo hago así:

header('HTTP/1.1 401 Unauthorized');
header('Location: /');

El servidor envía un 302 Found con Location, así que no un 401 Unauthorized.

Si lo hago así:

header('Location: /');
header('HTTP/1.1 401 Unauthorized');

El navegador recibe un 401 Unauthorized y a Location, pero no redirige.

(IE 9 y Chrome 16 se comportan igual, así que supongo que es correcto)

Tal vez estoy haciendo un mal uso de HTTP? Me gustaría que la interfaz de mi aplicación sea exactamente la misma para todos los clientes:, navegador moderno, llamadas API, etc. El texto de respuesta 401 + le diría a un usuario de API qué es qué. La redirección es útil para un navegador.

¿Hay un camino (bueno)?

Author: Rudie, 2012-01-08

8 answers

Por definición (ver RFC 2616), el código de respuesta HTTP 302 es el código de redirección. Sin él, el encabezado de ubicación puede ser ignorado.

Sin embargo, puede enviar una respuesta HTTP 401 y aún mostrar la salida. En lugar de redirigir al usuario a una página de error, simplemente podría escribir el contenido que desea enviar en el cuerpo HTTP en la misma solicitud.

 26
Author: David Chan,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-09-06 13:59:41

Voy a llegar muy tarde, pero pensé en añadir mis dos centavos. Según entiendo, el deseo es indicar que el usuario no tiene la autorización correcta y solicitarle que inicie sesión. Rudie comprensiblemente le gustaría devolver 401 No autorizado (porque el usuario necesita autorizar por algún mecanismo, por ejemplo. iniciar sesión), y también reenviar a la página de inicio de sesión-pero esto no es muy fácil de lograr y no es compatible fuera de la caja por la mayoría de las bibliotecas. Una solución es mostrar la página de inicio de sesión en el cuerpo de la respuesta 401, como se sugirió en otra respuesta. Sin embargo, permítanme examinar esto desde la perspectiva de las prácticas establecidas/mejores.

Caso de Prueba 1: Facebook

Navegar a una página de Facebook protegida (mi perfil de usuario) mientras está desconectado resulta en una respuesta 404 Not Found. Facebook muestra una página de propósito general "esta página no está disponible", que también incluye un formulario de inicio de sesión. Interesante.... Aún más interesante: cuando navego a la página de "eventos", me sirve una respuesta 302 que reenvía a una página de inicio de sesión (que devuelve una respuesta de 200). Así que supongo que su idea es devolver 302 para las páginas que sabemos existen, pero servir 404 para las páginas que pueden o no existir (por ejemplo. para proteger la privacidad de un usuario).

Caso de prueba 2: Bandeja de entrada de Google

Navegar a mi bandeja de entrada cuando estoy desconectado devuelve 302 y me reenvía a una página de inicio de sesión, similar a Facebook. Yo no era capaz de averiguar cómo hacer mi Google+ perfil privado por lo que no hay datos de prueba allí...

Caso de Prueba 3: Amazon.com

Navegar a mi historial de pedidos cuando estoy desconectado devuelve 302 y me reenvía a una página de inicio de sesión como antes. Amazon no tiene el concepto de una página de "perfil", así que tampoco puedo probarlo aquí.

Para resumir los casos de prueba aquí, parece ser la mejor práctica para devolver un 302 Encontrado y reenviar a una página de inicio de sesión si el usuario necesita iniciar sesión (aunque yo diría que 303 Ver Otro es en realidad más adecuado). Por supuesto, esto es solo en el caso de que un usuario humano real necesite ingresar un nombre de usuario y una contraseña en un formulario html. Para otros tipos de autenticación(por ejemplo. básico, clave api, etc.), 401 No autorizado es obviamente la respuesta adecuada. En este caso no hay necesidad de reenviar a una página de inicio de sesión.

 10
Author: tytk,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-01-24 19:50:56

3xx significa Redireccionar
4xx significa que el navegador hizo algo mal.

Hay una razón por la que los códigos se dividen de la manera en que están-no se mezclan;)

 8
Author: Niet the Dark Absol,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-01-08 05:30:10

Además de las buenas respuestas de Kolink y David (+1), me gustaría señalar que está intentando cambiar la semántica del protocolo HTTP devolviendo un 401 Y diciéndole al navegador que redireccione. Así no es como se pretende que funcione el protocolo HTTP, y si encuentra una manera de obtener ese resultado, los clientes HTTP encontrarán que el comportamiento de su servicio no es estándar.

O bien envía un 401 y permite que el navegador se ocupe de él, o maneja la situación de manera diferente (por ejemplo, como sugirió un comentarista, redirigir a una página de inicio de sesión o tal vez a una página que explique por qué el usuario no tenía acceso).

 4
Author: Eric J.,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-01-08 05:46:10

Aquí hay un camino limpio:

En la página 401, puede elegir la "vista" para enviar en función del encabezado "aceptar" en la solicitud.

Si el accept es application/json, entonces puedes incluir el cuerpo:

{"status":401;"message":"Authentication required"}

Si el" aceptar " es text/html, entonces puedes incluir el cuerpo:

<form action="/signin" method="post">
    <!-- bla bla -->
    <input type="hidden" name="redirect" value="[URL ENCODE REQUEST URI]">
</form>

Entonces te encuentras con la misma pregunta... ¿se emite un 200 OK o un 302 Found en un inicio de sesión exitoso? (¿ves lo que hice allí? )

Si puede manejar la autenticación en cualquier página, solo puede tener el formulario acción sea la misma URL de página, pero esté atento a XSS si está poniendo el request_uri proporcionado por el usuario en el atributo acción del formulario.

 2
Author: Frank Forte,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-03-10 20:24:25

Puede enviar 401 y luego en el cuerpo de respuesta puede enviar window. location='domain.com'. Sin embargo, el usuario será redirigido inmediatamente sin saber que 401 ocurrió.

 1
Author: rkosegi,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-01-08 06:00:50

Los navegadores web no son clientes REST. Apégate al estado de envío 200 con un encabezado de ubicación y sin contenido de cuerpo. Los redireccionamientos 30x son para páginas que se han movido. No se debe esperar que otro código de estado/encabezado de ubicación redirija en un navegador web.

Alternativamente, su servidor web puede tener páginas de error configurables. Puede agregar javascript a la página de error para redirigir.

 1
Author: Jeff Harris,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-12-23 00:06:58

¿Podría ser esto lo que necesitas? Me encontré con esto antes con la misma pregunta.

if(user_has_no_rights()) 
{ 
   header('HTTP/1.1 401 Unauthorized');
   echo $this->requestAction('anothercontroller/action', 
array('return')); 

   $this->autoRender = false;
   $this->layout = ''; 
   die(); 
}
 0
Author: Josh,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-01-08 05:37:08