web-dev-qa-db-fra.com

Code de statut http correct pour la ressource nécessitant une autorisation

Il semble y avoir beaucoup de confusion quant au code de statut http correct à renvoyer si l'utilisateur tente d'accéder à une page nécessitant sa connexion.

Donc, fondamentalement, quel code d'état sera envoyé lorsque je montrerai la page de connexion?

Je suis presque sûr que nous devons utiliser un code de statut dans la plage 4xx.

Je ne parle pas d'authentification HTTP ici, donc c'est au moins 1 code d'état que nous n'allons pas utiliser (401 Unauthorized).

Maintenant, que devrions-nous utiliser? Les réponses (également ici sur SO) semblent varier:

Selon la réponse ici nous devrions utiliser 403 Forbidden.

Mais dans la description du code de statut est:

L'autorisation n'aidera pas et la demande NE DEVRAIT PAS être répétée.

Eh bien, cela ne ressemble pas au bon. Depuis l'autorisation aiderait.

Voyons donc une autre réponse. La réponse ici même n’utilise pas du tout la plage 4xx mais utilise plutôt 302 Found

La description du code d'état 302 Found:

La ressource demandée réside temporairement sous un autre URI. Étant donné que la redirection peut être modifiée à l'occasion, le client DEVRAIT continuer à utiliser l'URI de demande pour les futures demandes. Cette réponse ne peut être mise en cache que si elle est indiquée par un champ d'en-tête Cache-Control ou Expires.

Je pense que ce n'est pas non plus ce que je veux. Puisque ce n'est pas la ressource demandée qui réside sous un autre URI. Mais plutôt une ressource complètement différente (page de connexion vs page de contenu authentifié).

J'ai donc choisi une autre réponse étonnamment avec encore une autre solution.

Cette réponse suggère que nous choisissions 400 Bad Request.

La description de ce code d'état est la suivante:

La requête n'a pas pu être comprise par le serveur en raison d'une syntaxe mal formée. Le client NE DEVRAIT PAS répéter la demande sans modifications.

Je pense que le serveur a très bien compris la demande, mais refuse simplement de donner l'accès avant que l'utilisateur ne soit authentifié.

Un autre réponse indique également qu'une réponse 403 est correcte, mais elle se termine par:

S'il s'agit d'un site Web destiné au public, vous essayez de refuser l'accès sur la base d'un cookie de session [c'est ce que je fais] 200, avec un corps approprié pour indiquer qu'une connexion est nécessaire ou une redirection 302 temporaire vers une page de connexion est souvent nécessaire. meilleur.

Donc, 403 est correct, mais 200 ou 302 est LE MEILLEUR.

Hey! C'est ce que je recherche: LA MEILLEURE solution. Mais le meilleur ne devrait-il pas être identique au correct? Et pourquoi serait-ce le meilleur?

Merci à tous ceux qui ont si loin dans cette question :)

Je sais que je ne devrais pas trop m'en inquiéter. Et je pense que cette question est plus hypothétique (pas vraiment, mais l’a utilisée à cause de l’absence d’un meilleur mot).

Mais cette question me hante depuis quelque temps déjà.

Et si j’avais été un manager (qui ne faisait que reprendre des mots qui sonnaient comme ils le font toujours), j’aurais dit: mais, mais, mais, mais le repos est important. :-)

Alors, qu'est-ce que the right way™ d'utiliser un code d'état dans la situation ci-dessus (le cas échéant)?

tl; dr

Quelle est la réponse correcte du code de statut http lorsqu'un utilisateur tente d'accéder à une page nécessitant une connexion?

56
PeeHaa

Si l'utilisateur n'a fourni aucune information d'identification et que votre API en a besoin, retournez un 401 - Unauthorized. Cela incitera le client à le faire. Il y a généralement peu de débats sur ce scénario particulier.

Si l'utilisateur a fourni des informations d'identification valides mais insuffisant pour accéder à la ressource demandée (les informations d'identification concernaient peut-être un compte freemium mais la ressource demandée ne concernait que vos utilisateurs rémunérés), vous disposez de plusieurs options compte tenu du manque de souplesse. de certaines des définitions de code HTTP:

  1. Renvoie 403 - Forbidden. Ceci est plus descriptif et est généralement compris comme "les informations d'identification fournies étaient valides mais n'étaient pas encore suffisantes pour accorder l'accès"
  2. Renvoie 401 - Unauthorized. Si vous êtes paranoïaque à propos de la sécurité, vous ne voudrez peut-être pas redonner au client les informations supplémentaires telles qu'elles ont été renvoyées dans (1) ci-dessus.
  3. Renvoyez 401 ou 403, mais avec des informations utiles dans le corps de la réponse, décrivant les raisons pour lesquelles l'accès est refusé. Encore une fois, cette information peut être plus que ce que vous voudriez fournir au cas où elle aiderait un peu les attaquants.

Personnellement, j'ai toujours utilisé # 1 pour le scénario dans lequel des informations d'identification valides ont été transmises, mais le compte auquel elles sont associées n'a pas accès à la ressource demandée.

43
Brian Kelly

Vous demandez «le meilleur», «le bon chemin» et «le bon», ce qui complique la réponse à cette question, car ces critères ne sont pas nécessairement interchangeables et peuvent même être conflictuels - en particulier en ce qui concerne le repos. .

La "meilleure" réponse dépend de votre application. Êtes-vous en train de créer une application Web Plain Old Browser-Based (POBB)? Construisez-vous un client natif (par exemple iOS ou Android) et utilisez-vous un service sur le Web? Utilisez-vous intensément AJAX pour générer des mises à jour de pages Web? Est curl le client visé?

Supposons que vous construisez une application Web traditionnelle. Regardons comment Google le fait (sortie hachée par souci de brièveté):

$ 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 nous a d'abord redirigé vers la "vraie" URL de GMail (en utilisant une redirection 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&ltmpl=default&ltmplcache=2
< Content-Type: text/html; charset=UTF-8
< Content-Length: 352
< ...

Et puis il nous redirige vers la page de connexion (en utilisant une redirection 302).

$ curl -v 'https://accounts.google.com/ServiceLogin?service=mail&passive=true&rm=false&continue=http://mail.google.com/mail/&scc=1&ltmpl=default&ltmplcache=2'
< HTTP/1.1 200 OK
< Content-Type: text/html; charset=UTF-8
< Transfer-Encoding: chunked
< ...

La page de connexion elle-même est livrée avec le code de statut 200!

Pourquoi cette façon?

Du point de vue de l'expérience utilisateur, si un utilisateur accède à une page qu'il ne peut pas afficher car il n'est pas authentifié, vous voulez l'apporter à une page lui permettant de corriger ce problème (en se connectant). Dans cet exemple, la page de connexion est autonome et n’est qu’une autre page (c’est pourquoi 200 convient mieux).

Vous pouvez afficher une page 4XX avec une explication et un lien vers la page de connexion. Cela pourrait, en fait, sembler plus reposant. Mais c'est une expérience utilisateur pire.

Ok, mais y at-il un cas où quelque chose comme 403 est logique? Absolument.

Tout d’abord, notez que 403 n’est pas bien défini dans la spécification. Afin de comprendre comment il devrait être utilisé, vous devez regarder comment il est mis en œuvre sur le terrain.

403 est couramment utilisé par les serveurs Web tels qu'Apache et IIS comme code d'état pour les pages renvoyées lorsque le navigateur demande une liste de répertoires (un URI se terminant par "/") mais que les listes de répertoires du serveur sont désactivées. Dans ce cas, le 403 est vraiment un 404 spécialisé, et vous ne pouvez pas faire grand chose pour l'utilisateur, sauf lui faire savoir ce qui ne va pas.

Cependant, voici un exemple de site qui utilise le 403 pour indiquer à l'utilisateur qu'il/elle n'a pas les privilèges suffisants et les mesures à prendre pour corriger la situation (consultez le réponse complète pour plus de détails):

curl -v http://www.w3.org/Protocols/rfc2616/
< HTTP/1.1 403 Forbidden
< Content-Type: text/html; charset=iso-8859-1
< Content-Length: 1564
< ...

(En passant, 403 apparaît également dans les API Web, comme l’API de Twitter; ici, 403 signifie "La demande est comprise, mais elle a été refusée. Un message d’erreur associé expliquera pourquoi. Ce code est utilisé lorsque les demandes sont être refusé en raison de limites de mise à jour. ")

En guise d’amélioration, supposons toutefois que vous ne souhaitiez pas rediriger l’utilisateur vers une page de connexion, ni le forcer à suivre un lien vers la page de connexion. Au lieu de cela, vous souhaitez afficher le formulaire de connexion sur la page que l'utilisateur ne peut pas voir. S'ils s'authentifient avec succès, ils voient le contenu lorsque la page est rechargée. s'ils échouent, ils récupèrent le formulaire de connexion. Ils ne naviguent jamais vers une autre URL.

Dans ce cas, un code de statut de 403 a beaucoup de sens et est homologue au cas de 401, avec l'avertissement que le navigateur ne fera pas apparaître une boîte de dialogue demandant à l'utilisateur de s'authentifier - le formulaire se trouve dans la page elle-même. .

Cette approche de l’authentification n’est pas courante, mais elle pourrait avoir un sens et elle est préférable, à mon humble avis, aux solutions de modal de connexion javascript à la connexion que les développeurs tentent d’implémenter.

Cela revient à la question: voulez-vous rediriger ou non?

Autres: réflexions sur le code d'état 401 ...

Le code d'état 401 - et l'authentification de base/digest associée - a de nombreux avantages. Il est adopté par la spécification HTTP, il est pris en charge par tous les principaux navigateurs, il n'est pas fondamentalement non-RESTful ... Le problème est que, du point de vue de l'expérience utilisateur, il est très très peu attrayant. Il y a le dialogue pop-up non stylable et cryptique, le manque d'une solution élégante pour la déconnexion, etc. Si vous (ou vos parties prenantes/clients) pouvez vivre avec ces problèmes (un gros si), alors cela pourrait être qualifié de "correct". " Solution.

26
toddsundsted

D'accord. REST est juste un style, pas un protocole strict. De nombreux services Web publics s’écartent de ce style. Vous pouvez construire votre service pour retourner ce que vous voulez. Assurez-vous simplement que vos clients savent quels codes de retour s'attendre.

Personnellement, j'ai toujours utilisé 401 (non autorisé) pour indiquer qu'un utilisateur non authentifié avait demandé une ressource nécessitant une connexion. J'ai ensuite besoin de l'application cliente pour guider l'utilisateur vers la connexion.

J'utilise 400 (mauvaise demande) en réponse à une tentative d'ouverture de session avec des informations d'identification non valides.

HTTP 302 (déplacé) semble plus approprié pour les applications Web où le client est un navigateur. Les navigateurs suivent généralement l'adresse de réacheminement dans la réponse. Cela peut être utile pour guider l'utilisateur vers une page de connexion.

10
EJK

Je ne parle pas d'authentification HTTP ici, c'est donc au moins 1 code d'état que nous n'allons pas utiliser (401 non autorisé).

Faux. 401 fait partie du protocole de transfert hypertexte (RFC 2616 Fielding, et autres), mais ne se limite pas à l'authentification HTTP. De plus, c'est le seul code d'état indiquant que la demande nécessite une authentification de l'utilisateur.

Les codes 302 et 200 pourraient être utilisés et seraient plus faciles à implémenter dans certains scénarios, mais pas tous. Et si vous voulez respecter les spécifications, 401 est la seule réponse correcte qui soit.

Et 403 est en effet le code le plus erroné à renvoyer. Comme vous l'avez bien dit ...

L'autorisation n'aidera pas et la demande NE DEVRAIT PAS être répétée.

Donc, cela n'est clairement pas approprié pour indiquer que l'autorisation est une option.

Je respecterais la norme: 401 non autorisé

-

METTRE &AGRAVE; JOUR

Pour ajouter un peu plus d'informations, en levant la confusion liée à ...

La réponse DOIT inclure un champ d'en-tête WWW-Authenticate (paragraphe 14.47) contenant un défi applicable à la ressource demandée.

Si vous pensez que cela va vous empêcher d'utiliser un 401, vous devez vous rappeler qu'il y a plus:

"La valeur du champ comprend au moins un défi qui indique le ou les schémas d'authentification et les paramètres applicables à l'URI de la demande." 

Cette "indication du ou des schémas d'authentification" signifie que vous pouvez choisir d'autres schémas d'authentification! 

Le protocole HTTP (RFC 2616) définit un cadre simple pour les schémas d'authentification d'accès, mais vous n'avez PAS À UTILISER CE cadre. 

En d'autres termes: vous n'êtes pas lié à l'habituel WWW-Auth. Vous devez simplement indiquer comment votre application Web fait son autorisation et offrir les données correspondantes dans l'en-tête, c'est tout. Selon les spécifications, en utilisant un 401, vous pouvez choisir votre propre poison d'autorisation! Et c’est là que votre "webapp" peut faire ce que VOUS voulez, en ce qui concerne l’en-tête 401 et la mise en œuvre de votre autorisation. 

Ne laissez pas les spécifications vous confondre, en pensant que vous devez utiliser le schéma d'authentification HTTP habituel. Vous pas! La seule chose que les spécifications appliquent réellement: vous DEVEZ/DOIT simplement identifier le schéma d’authentification de votre application Web et transmettre les paramètres associés pour permettre à la partie qui fait la demande de lancer des tentatives d’autorisation potentielles. 

Et si vous n'êtes toujours pas sûr, je peux placer tout cela dans une perspective simple mais compréhensible: supposons que vous inventiez un nouveau régime d'autorisation demain, les spécifications vous permettent de l'utiliser également. Si les spécifications avaient restreint la mise en œuvre de ces nouvelles implémentations de technologie d'autorisation, ces spécifications auraient été modifiées il y a bien longtemps. Les spécifications définissent des normes, mais elles ne limitent pas vraiment la multitude d'applications potentielles.

8
user1093284

Votre "TL; DR" ne correspond pas à la version "TL".

La réponse appropriée pour demander une ressource pour laquelle vous avez besoin d'une autorisation est 401.

302 n’est pas la bonne réponse, car, en fait, la ressource n’est pas disponible ailleurs. L'URL d'origine était correcte, le client n'avait tout simplement pas les droits. Si vous suivez la redirection, vous n'obtenez pas réellement ce que vous recherchez. Vous vous retrouvez dans un flux de travail ad hoc qui n'a rien à voir avec la ressource.

403 est incorrect. 403 est l'erreur "ne peut pas y arriver d'ici". Tu ne peux tout simplement pas voir ça, je me fiche de qui tu es. Certains diront que 403 et 404 sont similaires. La différence réside simplement avec 403, le serveur dit «oui, je l’ai, mais vous ne pouvez pas», alors que 404 dit «je ne sais rien de ce dont vous parlez». Les fous de sécurité diront que le 404 est "plus sûr". Pourquoi leur dire quelque chose qu'ils n'ont pas besoin de savoir.

Le problème que vous rencontrez n'a rien à voir avec REST ou HTTP. Votre problème est d’essayer d’établir une relation dynamique entre le client et le serveur, qui se manifeste à la fin par un cookie. La totalité de la ressource -> 302 -> La page de connexion est entièrement consacrée à l’expérience utilisateur, qui utilise le piratage Web, le navigateur Web, qui se présente sous la forme stock, un client HTTP moche et un participant REST moche. 

HTTP a un mécanisme d'autorisation. L'en-tête d'autorisation. L'expérience utilisateur autour d'elle, dans un navigateur générique, est affreuse. Donc personne ne l'utilise. 

Donc, il n'y a pas de réponse HTTP appropriée (bien, il y en a 401, mais vous ne pouvez/ne pouvez pas l'utiliser). La réponse REST n'est pas correcte, car REST repose généralement sur le protocole sous-jacent (HTTP dans ce cas, mais nous l'avons déjà abordé).

Alors. 302 -> 200 pour la page de connexion est tout ce qu'elle a écrit. C'est ce que tu as. Si vous n'utilisiez pas le navigateur ou si vous utilisiez tout via XHR ou un autre client personnalisé, cela ne poserait pas de problème. Vous utiliseriez simplement l'en-tête Authorization, suivriez le protocole HTTP et utiliseriez un schéma tel que DIGEST ou qu'AWS utilise, pour le faire. Ensuite, vous pouvez utiliser les normes appropriées pour répondre à de telles questions.

3
Will Hartung

Comme vous l'avez fait remarquer, 403 Forbidden est explicitement défini par la phrase "L'autorisation n'aidera pas", mais il est à noter que les auteurs faisaient presque certainement ici référence à l'autorisation HTTP (ce qui n'aidera certainement pas, car votre site utilise régime d'autorisation différent). En effet, étant donné que le code de statut est un signal adressé à user agent plutôt qu’à user, un tel code serait correct dans la mesure où toute autorisation que l’agent tentera de fournir n’aidera plus avec les exigences requises. processus d'autorisation (cf 401 Unauthorized).

Cependant, si vous prenez littéralement cette définition de 403 Forbidden et estimez qu'elle est toujours inappropriée, peut-être que 409 Conflict pourrait s'appliquer? Telle que définie dans RFC 2616 § 10.4.10 :

 La demande n'a pas pu être complétée en raison d'un conflit avec le fichier .__ en cours. état de la ressource. Ce code n'est autorisé que dans les situations où 
 l'utilisateur devrait pouvoir résoudre le conflit 
 et relancez la demande. Le corps de réponse DEVRAIT inclure suffisamment de 
 informations permettant à l'utilisateur de reconnaître la source du conflit .
 Idéalement, l'entité de réponse inclurait suffisamment d'informations pour le 
 utilisateur ou agent d'utilisateur pour résoudre le problème; cependant, cela pourrait ne pas être 
 possible et n'est pas obligatoire .

Il existe en effet un conflit avec l'état actuel de la ressource: la ressource est dans un état "verrouillé" et un tel conflit ne peut être "résolu" que si l'utilisateur fournit ses informations d'identification et soumet de nouveau la demande. Le corps contiendra "suffisamment d'informations pour que l'utilisateur puisse reconnaître la source du conflit" (il indiquera qu'ils ne sont pas connectés) et comprendra également "suffisamment d'informations pour l'utilisateur ou l'agent utilisateur pour résoudre le problème "(c'est-à-dire un formulaire de connexion).

3
eggyal

Ta Réponse:

401 Unauthorized surtout si vous vous en fichez ou si vous ne redirigerez pas les gens vers une page de connexion 

-ou- 

302 Found pour impliquer qu'il y avait la ressource, mais ils doivent fournir les informations d'identification pour pouvoir y retourner. Ne le faites que si vous utilisez une redirection et veillez à fournir les informations appropriées dans le corps de la réponse.


Autres suggestions:

401 Unauthorized est généralement utilisé pour les ressources auxquelles l'utilisateur n'a pas accès après le traitement de l'authentification.

403 Forbidden est un peu obscur pour moi en toute honnêteté. Je l'utilise lorsque je verrouille des ressources au niveau du système de fichiers et, comme le dit votre message, "l'autorisation n'aide pas".

400 Bad Request est inapproprié car la nécessité de se connecter ne représente pas une syntaxe mal formée.

0
one.beat.consumer

Je crois que 401 est le code de statut correct à renvoyer après une autorisation échouée. Référence RFC 2616 section-14.8 Elle lit "Un agent d'utilisateur qui souhaite s'authentifier auprès d'un serveur - généralement, mais pas nécessairement, après avoir reçu une réponse 401

0
Julius Depulla