restful - Corregir el código de estado http para el recurso que requiere autorización
possible http status codes (8)
Parece que hay mucha confusión acerca del código de estado HTTP correcto para devolver si el usuario intenta acceder a una página que requiere que el usuario inicie sesión.
Entonces, básicamente, ¿qué código de estado se enviará cuando muestre la página de inicio de sesión?
Estoy bastante seguro de que necesitamos usar un código de estado en el rango 4xx
.
No estoy hablando de autenticación HTTP aquí, así que al menos hay 1 código de estado que no vamos a usar ( 401 Unauthorized
).
Ahora, ¿qué deberíamos usar? Las respuestas (también aquí en SO) parecen variar:
Según la respuesta here deberíamos usar 403 Forbidden
.
Pero en la descripción del código de estado es:
La autorización no ayudará y la solicitud NO DEBE repetirse.
Bueno, eso no se ve como el correcto. Dado que la autorización PODRÍA ayudar.
Entonces, veamos alguna otra respuesta. La respuesta here incluso no usa el rango 4xx
en absoluto, sino que usa 302 Found
La descripción del código de estado 302 Found
:
El recurso solicitado reside temporalmente bajo un URI diferente. Como la redirección podría verse alterada ocasionalmente, el cliente DEBERÍA continuar utilizando el URI de solicitud para futuras solicitudes. Esta respuesta solo se puede almacenar en caché si está indicada por un campo de encabezado Cache-Control o Expires.
Creo que eso tampoco es lo que quiero. Dado que no es el recurso solicitado que reside en un URI diferente. Pero más bien un recurso completamente diferente (página de inicio de sesión vs página de contenido autenticado).
Así que avancé y escogí otra answer sorprendentemente con otra solución más.
Esta respuesta sugiere que elijamos 400 Bad Request
.
La descripción de este código de estado es:
La solicitud no pudo ser entendida por el servidor debido a una sintaxis mal formada. El cliente NO DEBE repetir la solicitud sin modificaciones.
Creo que el servidor entendió la solicitud muy bien, pero simplemente se niega a dar acceso antes de que el usuario sea autenticado.
Otra answer también dice que una respuesta 403
es correcta, sin embargo, termina con:
Si este es un sitio web público donde intenta denegar el acceso basado en una cookie de sesión [eso es lo que hago], 200 con un cuerpo apropiado para indicar que es necesario iniciar sesión o un 302 redireccionamiento temporal a una página de inicio de sesión es a menudo mejor.
Entonces 403
es correcto, pero 200
o 302
es EL MEJOR.
¡Oye! Eso es lo que estoy buscando: LA MEJOR solución. Pero, ¿no debería ser el mejor el correcto? ¿Y por qué sería el mejor?
Gracias a todos los que han llegado hasta aquí en esta pregunta :)
Sé que no debería preocuparme demasiado por eso. Y creo que esta pregunta es más hipotética (en realidad no, pero la usé por falta de una palabra mejor).
Pero esta pregunta me está inquietando desde hace un tiempo.
Y si hubiera sido un gerente (que acaba de tomar algunas palabras que suenan bien, como siempre lo hacen), hubiera dicho: pero, pero, pero, pero la tranquilidad es importante. :-)
Entonces, ¿cuál es the right way™
de usar un código de estado en la situación anterior (si corresponde)?
tl; dr
¿Cuál es la respuesta correcta del código de estado http cuando un usuario intenta acceder a una página que requiere iniciar sesión?
No estoy hablando de autenticación HTTP aquí, así que al menos hay 1 código de estado que no vamos a usar (401 no autorizado).
Incorrecto. 401 es parte del Protocolo de transferencia de hipertexto (RFC 2616 Fielding, et al.), Pero no se limita a la autenticación HTTP. Además, es el único código de estado que indica que la solicitud requiere autenticación de usuario.
Los códigos 302 y 200 podrían usarse y es más fácil de implementar en algunos escenarios, pero no en todos. Y si quiere obedecer las especificaciones, 401 es la única respuesta correcta que hay.
Y 403 es de hecho el código más incorrecto para regresar. Como dijiste correctamente ...
La autorización no ayudará y la solicitud NO DEBE repetirse.
Entonces, esto claramente no es adecuado para indicar que la autorización es una opción.
Me quedaría con el estándar: 401 no autorizado
-
ACTUALIZAR
Para agregar un poco más de información, eliminando la confusión relacionada con ...
La respuesta DEBE incluir un campo de encabezado WWW-Authenticate (sección 14.47) que contenga un desafío aplicable al recurso solicitado.
Si crees que esto te impedirá usar un 401, debes recordar que hay más:
"El valor del campo consiste en al menos un desafío que indica el (los) esquema (s) de autenticación y los parámetros aplicables al URI de solicitud".
¡Esto "indicando el (los) esquema (s) de autenticación" significa que puede optar por otros esquemas de autenticación!
El protocolo HTTP (RFC 2616) define un marco simple para los esquemas de autenticación de acceso, pero NO TIENE que usar ESA estructura.
En otras palabras: no estás obligado a la WWW-Auth habitual. Solo DEBE indicar CÓMO su aplicación web es su autorización y ofrecer los datos correspondientes en el encabezado, eso es todo. De acuerdo con las especificaciones, usando un 401, ¡puede elegir su propio veneno de autorización! Y ahí es donde su "aplicación web" puede hacer lo que USTED desea que haga cuando se trata del encabezado 401 y la implementación de su autorización.
No permita que las especificaciones lo confundan, pensando que TIENE que usar el esquema de autenticación HTTP habitual. Tu no! Lo único que las especificaciones realmente imponen: usted SOLO TIENE / DEBE identificar el esquema de autenticación de su webapp y transmitir los parámetros relacionados para permitir que la parte solicitante inicie posibles intentos de autorización.
Y si todavía no está seguro, puedo poner todo esto en una perspectiva simple pero comprensible: digamos que va a inventar un nuevo esquema de autorización mañana, luego las especificaciones le permiten usar eso también. Si las especificaciones hubieran restringido la implementación de tales nuevas implementaciones de tecnología de autorización, esas especificaciones se habrían modificado hace siglos. Las especificaciones definen estándares, pero en realidad no limitan la multitud de posibles implementaciones.
A su vez, pides "lo mejor", "el camino correcto" y "lo correcto", lo que hace difícil responder a esta pregunta porque esos criterios no son necesariamente intercambiables y pueden, de hecho, entrar en conflicto, especialmente cuando se trata de RESTfulness .
La "mejor" respuesta depende de su aplicación. ¿Está construyendo una aplicación web basada en el navegador antiguo (POBB)? ¿Está creando un cliente nativo (por ejemplo, iOS o Android) y accediendo a un servicio a través de la Web? ¿Haces un uso intensivo de AJAX para conducir actualizaciones de páginas web? ¿Curl es el cliente deseado?
Supongamos que está creando una aplicación web tradicional. Veamos cómo lo hace Google (salida cortada para abreviar):
$ curl -v http://gmail.com/
< HTTP/1.1 301 Moved Permanently
< Location: http://mail.google.com/mail/
< Content-Type: text/html; charset=UTF-8
< Content-Length: 225
< ...
Google primero nos redirige a la URL "verdadera" para GMail (utilizando un redireccionamiento 302).
$ curl -v http://mail.google.com/mail/
< HTTP/1.1 302 Moved Temporarily
< Location: https://accounts.google.com/ServiceLogin?service=mail&passive=true&rm=false&continue=http://mail.google.com/mail/&scc=1<mpl=default<mplcache=2
< Content-Type: text/html; charset=UTF-8
< Content-Length: 352
< ...
Y luego nos redirige a la página de inicio de sesión (usando un redireccionamiento 302).
$ curl -v ''https://accounts.google.com/ServiceLogin?service=mail&passive=true&rm=false&continue=http://mail.google.com/mail/&scc=1<mpl=default<mplcache=2''
< HTTP/1.1 200 OK
< Content-Type: text/html; charset=UTF-8
< Transfer-Encoding: chunked
< ...
¡La página de inicio de sesión se entrega con el código de estado 200 !
¿Por qué de esta manera?
Desde la perspectiva de la experiencia del usuario, si un usuario va a una página que no puede ver porque no está autenticado, desea llevar al usuario a una página que le permita corregir esto (mediante el inicio de sesión). En este ejemplo, la página de inicio de sesión está solo y es solo otra página (por lo que 200 es apropiado).
Podría lanzar una página 4XX con una explicación y un enlace a la página de inicio de sesión. Eso podría, de hecho, parecer más RESTful. Pero es una peor experiencia de usuario.
Ok, pero ¿hay algún caso en que algo como 403 tenga sentido? Absolutamente.
Primero, sin embargo, tenga en cuenta que 403 no está bien definido en la especificación. Para entender cómo se debe usar, debes ver cómo se implementa en el campo.
403 es comúnmente utilizado por los servidores web como Apache e IIS como el código de estado para las páginas devueltas cuando el navegador solicita una lista de directorio (un URI que termina en "/") pero el servidor tiene listas de directorios deshabilitadas. En este caso, 403 es realmente un 404 especializado, y no hay mucho que pueda hacer por el usuario, excepto que sepa lo que salió mal.
Sin embargo, aquí hay un ejemplo de un sitio que usa el 403 para indicar al usuario que no tiene privilegios suficientes y qué medidas tomar para corregir la situación (consulte la respuesta completa para obtener más información):
curl -v http://www.w3.org/Protocols/rfc2616/
< HTTP/1.1 403 Forbidden
< Content-Type: text/html; charset=iso-8859-1
< Content-Length: 1564
< ...
(Por otro lado, 403 también se ve en API basadas en web, como la API de Twitter; aquí, 403 significa "La solicitud es entendida, pero ha sido rechazada. Un mensaje de error adjunto explicará por qué. Este código se usa cuando las solicitudes son siendo denegado debido a los límites de actualización. ")
Como mejora, supongamos, sin embargo, que no desea redirigir al usuario a una página de inicio de sesión, ni forzar al usuario a seguir un enlace a la página de inicio de sesión. En su lugar, desea mostrar el formulario de inicio de sesión en la página que el usuario no puede ver. Si se autentican con éxito, ven el contenido cuando la página se recarga; si fallan, obtienen el formulario de inicio de sesión nuevamente. Nunca navegan a otra URL.
En este caso, un código de estado de 403 tiene mucho sentido, y es homólogo al caso 401, con la advertencia de que el navegador no abrirá un cuadro de diálogo pidiendo al usuario que se autentique: el formulario está en la página misma. .
Este enfoque de autenticación no es común, pero podría tener sentido, y es IMHO preferible a las soluciones pop-up-a-javascript-modal-to-log-in que los desarrolladores intentan implementar.
Todo se reduce a la pregunta, ¿quieres redirigir o no?
Adicional: pensamientos sobre el código de estado 401 ...
El código de estado 401 - y la autenticación básica / resumida asociada - tiene muchas cosas a su favor. Está aceptado por la especificación HTTP, es compatible con todos los principales navegadores, no es inherentemente no RESTful ... El problema es que, desde la perspectiva de la experiencia del usuario, es muy poco atractivo. Existe el diálogo pop-up poco sofisticado y críptico, la falta de una solución elegante para cerrar la sesión, etc. Si usted (o sus partes interesadas / clientes) pueden vivir con esos problemas (un gran sí) entonces podría calificar como el "correcto" "solución".
Como usted señala, 403 Forbidden
se define explícitamente con la frase " Authorization will not help ", pero vale la pena señalar que los autores casi con certeza se referían aquí a la autorización HTTP (que de hecho no ayudará ya que su sitio utiliza un esquema de autorización diferente ) De hecho, dado que el código de estado es una señal para el agente usuario en lugar del usuario , dicho código sería correcto en la medida en que cualquier autorización que el agente intente proporcionar no ayudará más con el proceso de autorización requerido (cf 401 Unauthorized
).
Sin embargo, si toma literalmente la definición de 403 Forbidden
y siente que todavía es inapropiada, ¿quizás podría aplicarse 409 Conflict
? Como se define en RFC 2616 §10.4.10 :
The request could not be completed due to a conflict with the current state of the resource. This code is only allowed in situations where it is expected that the user might be able to resolve the conflict and resubmit the request. The response body SHOULD include enough information for the user to recognize the source of the conflict. Ideally, the response entity would include enough information for the user or user agent to fix the problem; however, that might not be possible and is not required.
De hecho, hay un conflicto con el estado actual del recurso: el recurso está en un estado "bloqueado" y dicho conflicto solo puede "resolverse" a través del usuario que proporciona sus credenciales y vuelve a enviar la solicitud. El cuerpo incluirá " información suficiente para que el usuario reconozca el origen del conflicto " (indicará que no ha iniciado sesión) y, de hecho, también incluirá " información suficiente para que el usuario o el agente de usuario corrijan el problema " ( es decir, un formulario de inicio de sesión).
Convenido. REST es solo un estilo, no un protocolo estricto. Muchos servicios web públicos se desvían de este estilo. Puedes construir tu servicio para devolver lo que quieras. Solo asegúrate de que tus clientes sepan qué códigos de retorno esperar.
Personalmente, siempre he usado 401 (no autorizado) para indicar que un usuario no autenticado ha solicitado un recurso que requiere un inicio de sesión. Luego solicito a la aplicación cliente que guíe al usuario al inicio de sesión.
Uso 400 (solicitud incorrecta) en respuesta a un intento de inicio de sesión con credenciales no válidas.
HTTP 302 (movido) parece más apropiado para aplicaciones web donde el cliente es un navegador. Los navegadores suelen seguir la dirección de redireccionamiento en la respuesta. Esto puede ser útil para guiar al usuario a una página de inicio de sesión.
Creo que 401 es el código de estado correcto para devolver la autorización fallida. Referencia RFC 2616 sección-14.8 Se lee "Un agente de usuario que desea autenticarse con un servidor-- por lo general, pero no necesariamente, después de recibir una respuesta 401 "
Si el usuario no ha proporcionado ninguna credencial y su API lo requiere, devuelva un 401 - Unauthorized
. Eso desafiará al cliente a hacerlo. Por lo general, hay poco debate sobre este escenario en particular.
Si el usuario ha proporcionado credenciales válidas pero no son suficientes para acceder al recurso solicitado (tal vez las credenciales eran para una cuenta freemium pero el recurso solicitado es solo para usuarios pagados), tiene un par de opciones dada la holgura de algunas de las Definiciones del código HTTP:
- Retorno
403 - Forbidden
. Esto es más descriptivo y se entiende generalmente como "las credenciales suministradas eran válidas, pero aún así no eran suficientes para permitir el acceso". - Retorno
401 - Unauthorized
. Si es paranoico con respecto a la seguridad, es posible que no desee devolver la información adicional al cliente como se devolvió en (1) arriba. - Devuelva
401
o403
pero con información útil en el cuerpo de respuesta describiendo las razones por las cuales se niega el acceso. Una vez más, esa información podría ser más de lo que quisieras proporcionar en caso de que ayude un poco a los atacantes.
Personalmente, siempre utilicé el n. ° 1 para el escenario donde se aprobaron las credenciales válidas, pero la cuenta a la que están asociadas no tiene acceso al recurso solicitado.
Su "TL; DR" no coincide con la versión "TL".
La respuesta adecuada para solicitar un recurso que necesita autorización para solicitar es 401.
302 no es la respuesta adecuada, porque, de hecho, el recurso no está disponible en otro lugar. La URL original era correcta, el cliente simplemente no tenía los derechos. Si sigues el redireccionamiento, en realidad no obtienes lo que estás buscando. Te dejan caer en un flujo de trabajo ad hoc que no tiene nada que ver con el recurso.
403 es incorrecto. 403 es el error "no se puede llegar desde aquí". Simplemente no puedes ver esto, no me importa quién eres. Algunos argumentarían que 403 y 404 son similares. La diferencia es simplemente con 403, el servidor dice "sí, lo tengo, pero no puedes", mientras que 404 dice "No sé nada de lo que estás hablando". Los expertos en seguridad dirían que 404 es "más seguro". Por qué decirles algo que no necesitan saber.
El problema con el que se encuentra no tiene nada que ver con REST o HTTP. Su problema es tratar de establecer una relación de estado entre el cliente y el servidor, que se manifiesta al final a través de algunas cookies. El recurso completo -> 302 -> página de inicio de sesión se trata de la experiencia del usuario utilizando el hack que se conoce como el navegador web, que resulta ser ambos, en forma de stock, un pésimo cliente HTTP y un pésimo participante REST.
HTTP tiene un mecanismo de autorización. El encabezado de Autorización. La experiencia del usuario a su alrededor, en un navegador genérico, es horrible. Entonces nadie lo usa
Entonces, no hay una respuesta HTTP adecuada (bueno, hay, 401, pero no puedo / no puedo usar eso). No hay una respuesta REST apropiada, ya que REST normalmente depende del protocolo subyacente (HTTP en este caso, pero ya lo hemos abordado).
Asi que. 302 -> 200 para la página de inicio de sesión es todo lo que ella escribió. Eso es lo que obtienes. Si no estuvieras usando el navegador, o hicieras todo a través de XHR o algún otro cliente personalizado, esto no sería un problema. Simplemente usaría el encabezado Autorización, seguiría el protocolo HTTP y aprovecharía un esquema como DIGEST o lo que usa AWS, y listo. Entonces puede usar los estándares apropiados para responder preguntas como estas.
Tu respuesta:
401 Unauthorized
especialmente si no le importa o no va a redireccionar personas a una página de inicio de sesión
-o-
302 Found
que implicaba que existía el recurso, pero necesitan proporcionar las credenciales para devolverlo. Haga esto solo si va a utilizar una redirección y asegúrese de proporcionar la información adecuada en el cuerpo de la respuesta.
Otras sugerencias:
401 Unauthorized
generalmente se usa para recursos a los que el usuario no tiene acceso después de manejar la autenticación.
403 Forbidden
es un poco oscuro para mí en honestidad. Lo uso cuando bloqueo recursos desde el nivel del sistema de archivos, y al igual que su publicación, "la autorización no ayuda".
400 Bad Request
es inapropiado, ya que la necesidad de iniciar sesión no representa la sintaxis mal formada.