web-dev-qa-db-fra.com

Est-il possible d'envoyer une redirection 401 non autorisée ET (avec une localisation)?

Je voudrais envoyer un 401 Unauthorized et rediriger le client quelque part. Toutefois:

si je le fais comme ça:

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

le serveur envoie un 302 Found avec Location, donc pas un 401 Unauthorized.

Si je le fais comme ça:

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

le navigateur reçoit à la fois un 401 Unauthorized et une Location, mais ne redirige pas.

(IE 9 et Chrome 16 se comportent de la même manière, donc je suppose que c'est correct)

Peut-être que j'utilise mal HTTP? Je souhaite que l'interface de l'application soit identique pour tous les clients: navigateur de texte, navigateur moderne, appels d'API, etc. La redirection est utile pour un navigateur.

Y a-t-il un (bon) moyen?

35
Rudie

Par définition (voir RFC 2616 ), le code de réponse HTTP 302est le code de redirection. Sans lui, l'en-tête d'emplacement peut être ignoré.

Cependant, vous pouvez envoyer une réponse HTTP 401 tout en affichant le résultat. Au lieu de rediriger l'utilisateur vers une page d'erreur, vous pouvez simplement écrire le contenu que vous souhaitez envoyer dans le corps HTTP dans la même demande.

27
David Chan

J'arrive très tard mais je pensais ajouter mes deux sous. Si je comprends bien, le souhait est d'indiquer que l'utilisateur ne dispose pas de la bonne autorisation et de l'inviter à se connecter. Naturellement, Ruddie souhaite renvoyer 401 non autorisé (car l'utilisateur doit autoriser par un mécanisme quelconque, par exemple la journalisation. dans) et les transférer également à la page de connexion - mais ceci n’est pas très facile à réaliser et n’est pas pris en charge immédiatement par la plupart des bibliothèques. Une solution consiste à afficher la page de connexion dans le corps de la réponse 401, comme suggéré dans une autre réponse. Cependant, permettez-moi d’examiner la question sous l’angle des meilleures pratiques établies.

Cas de test 1: Facebook

Accéder à une page Facebook protégée (mon profil utilisateur) en étant déconnecté entraîne une réponse 404 Introuvable. Facebook sert une page générale "cette page n'est pas disponible", qui comprend également un formulaire de connexion. Intéressant. Encore plus intéressant: lorsque je navigue vers la page "événements", une réponse 302 est envoyée et transmise à une page de connexion (qui renvoie une réponse 200). Je suppose donc que leur idée est de renvoyer 302 pour les pages que nous savons que existons, mais servons 404 pour les pages qui peuvent ou non exister (par exemple, pour protéger la vie privée d’un utilisateur).

Cas de test 2: Google Inbox

Lorsque je me connecte à ma boîte de réception lorsque je suis déconnecté, je retourne 302 pages et me renvoie à une page de connexion similaire à Facebook. Je ne savais pas comment rendre mon profil Google+ privé, donc pas de données de test là-bas ...

Cas de test 3: Amazon.com

Lorsque je me connecte à l'historique des commandes lorsque je suis déconnecté, je retourne 302 et me renvoie à la page de connexion comme auparavant. Amazon n'a pas de concept de "profil", donc je ne peux pas le tester ici non plus.

Pour résumer les cas de test, il semble préférable de renvoyer un message 302 trouvé et de le transférer vers une page de connexion si l'utilisateur doit se connecter (bien que je dirais que 303 Voir autre est en fait plus approprié). Ceci est bien sûr juste dans le cas où un utilisateur humain réel doit saisir un nom d'utilisateur et un mot de passe sous une forme html. Pour les autres types d'authentification (p. Ex. Base, clé d'api, etc.), 401 non autorisé est évidemment la réponse appropriée. Dans ce cas, il n'est pas nécessaire de transférer une page de connexion.

11
tytk

3xx signifie redirection
4xx signifie que le navigateur a fait quelque chose de mal.

Il y a une raison pour laquelle les codes sont divisés comme ils sont: ils ne se mélangent pas;)

6

En plus des réponses précises de Kolink et David (+1), je vous ferai remarquer que vous essayez de changer la sémantique du protocole HTTP en renvoyant un 401 ET en demandant au navigateur de se rediriger. Ce n'est pas ainsi que le protocole HTTP est censé fonctionner. Si vous trouvez un moyen d'obtenir ce résultat, les clients HTTP trouveront que le comportement de votre service est non standard.

Soit vous envoyez un 401 et autorisez le navigateur à le gérer, soit vous gérez la situation différemment (par exemple, comme l’a suggéré un intervenant, redirigez-vous vers une page de connexion ou peut-être une page expliquant pourquoi l’utilisateur n’a pas accès).

4
Eric J.

Voici un moyen propre:

Sur la page 401, vous pouvez choisir la "vue" à envoyer en fonction de l'en-tête "accepter" de la demande.

Si accept est application/json, vous pouvez alors inclure le corps:

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

Si "accepter" est text/html, vous pouvez alors inclure le corps:

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

Ensuite, vous rencontrez la même question ... émettez-vous un 200 OK ou un 302 Found sur une connexion réussie? (regarde ce que j'ai fait là? )

Si vous pouvez gérer l'authentification sur n'importe quelle page, vous pouvez simplement définir l'action de formulaire sur la même URL de page, mais sur watch for XSS si vous placez request_uri fourni par l'utilisateur dans l'attribut d'action de formulaire.

2
Frank Forte

Vous pouvez envoyer 401, puis dans le corps de la réponse, vous pouvez envoyer window.location = 'domain.com'. Cependant, l'utilisateur sera immédiatement redirigé sans savoir que 401 s'est produit.

1
rkosegi

Les navigateurs Web ne sont pas des clients REST. S'en tenir à l'envoi du statut 200 avec un en-tête Location et aucun corps du contenu. Les redirections 30x concernent les pages qui ont été déplacées. Aucun autre en-tête de code d'état ou d'emplacement ne devrait être redirigé dans un navigateur Web.

Alternativement, votre serveur Web peut avoir des pages d'erreur configurables. Vous pouvez ajouter du javascript à la page d'erreur pour le rediriger.

0
Jeff Harris