Reconnexion et authentification HTTP de base

Les développeurs Web sont conscients depuis longtemps du problÚme de la connexion et de la connexion aux sites protégés par HTTP Basic Authorization. Bien qu'il existe d'autres méthodes d'authentification qui ne souffrent pas de ce problÚme, l'autorisation de base reste souvent le meilleur choix. Le réseau dispose de suffisamment de matériel décrivant diverses solutions générales et particuliÚres. Mais tous, que j'ai trouvé, malheureusement, ne décrivent que des solutions partielles qui fonctionnent dans un navigateur et ne fonctionnent pas dans un autre. Sous cat je donne un résultat final généralisé de mes recherches sur ce problÚme

Je ferai une rĂ©servation tout de suite que je ne suis pas un dĂ©veloppeur front-end, et je ne suis pas allĂ© dans toute la variĂ©tĂ© des "marques" et des versions de navigateur. Uniquement avec des versions pertinentes au moment de la rĂ©daction. Pour la plupart des tĂąches Web, cela suffit. Pour les dĂ©veloppeurs qui ont besoin d'un support pour l'ensemble du "zoo" des navigateurs, l'article peut ĂȘtre un bon point de dĂ©part.

L'essence du problĂšme est que la norme d'autorisation de base HTTP ne prĂ©voit pas la journalisation. GĂ©nĂ©ralement. Lorsque vous accĂ©dez Ă  une page protĂ©gĂ©e par une autorisation de base, le navigateur lui-mĂȘme affiche sa propre fenĂȘtre avec une demande de connexion / mot de passe et, avec une connexion rĂ©ussie, les enregistre quelque part dans ses profondeurs. Ensuite, toutes les demandes ultĂ©rieures vers d'autres pages protĂ©gĂ©es de ce site utiliseront automatiquement ces valeurs dans l'en-tĂȘte Autorisation:
Autorisation: Basic bm9uZTpub25l
oĂč bm9uZTpub25l est le lien de connexion / mot de passe encodĂ© en base64 aucun: aucun (votre nom d'utilisateur et votre mot de passe peuvent ĂȘtre diffĂ©rents)

Pour vous connecter, il vous suffit de réinitialiser l'ancien nom d'utilisateur / mot de passe dans les profondeurs du navigateur et sur eux endroit pour en enregistrer de nouveaux. C'est là qu'une surprise nous attend. Puisqu'aucune norme ne régit cette action, chaque navigateur le fait à sa guise.

Pire encore, puisque la fenĂȘtre de demande de login / mot de passe est sa propre fenĂȘtre de navigateur, qui ne rĂ©pond dĂ©jĂ  qu'aux en-tĂȘtes de page HTTP, cette fenĂȘtre apparaĂźt avant tout traitement du corps de la page. Autrement dit, exĂ©cuter du javascript lors de la rĂ©ception d'une rĂ©ponse du serveur avec un Ă©tat de 401 ne fonctionne pas. Avant l'utilisateur, cette fenĂȘtre apparaĂźtra encore et encore avec une demande rĂ©pĂ©tĂ©e de connexion / mot de passe.

En fait, ce point est critique, car pour presque tous les navigateurs, la seule façon de se dĂ©connecter est d'envoyer une demande au serveur avec un login / mot de passe manifestement incorrect, de recevoir une rĂ©ponse du serveur avec le statut 401, puis de rĂ©initialiser le cache de login / mot de passe du navigateur. Mais si en mĂȘme temps le navigateur ne vous permet pas de traiter la rĂ©ponse 401 et de poursuivre le processus de connexion dĂ©jĂ  pour le nouvel utilisateur, en prenant le contrĂŽle mĂȘme au stade de la lecture des en-tĂȘtes HTTP et en lançant la forme mĂȘme d'autorisation dans laquelle vous le saisissez ne fonctionnera pas en face, alors ceci dĂ©jĂ  un problĂšme. Peu importe qu'il s'agisse d'une demande normale par rĂ©fĂ©rence ou XMLHttpRequest ou fetch. Le navigateur prend toujours le contrĂŽle au stade de l'analyse des en-tĂȘtes.

Donc


Donnée initiale:


  1. Il existe une page logout.html distincte sur laquelle toute la logique se trouve dans le script javascript, dont certaines parties sont données au cours de la présentation
  2. URL spécifiée - adresse de la page à rediriger aprÚs une connexion réussie
  3. Url401 est spécifié - l'adresse de la page qui renvoie toujours l'erreur HTTP 401 (non autorisée)

// file logout.html
const url = new URL("http://mysite.com/");
const url401 = new URL("http://mysite.com/401");

Internet Explorer


Notre produit ne nĂ©cessite pas de support pour ce navigateur, donc la solution que je n'ai pas personnellement testĂ©e. NĂ©anmoins, selon Google, il existe une solution, et c'est peut-ĂȘtre la plus simple et la plus Ă©lĂ©gante de toutes. De plus, je n'ai jamais rencontrĂ© d'informations indiquant que cette solution pour les navigateurs Microsoft a perdu de sa pertinence:

if (document.execCommand("ClearAuthenticationCache")) {
    window.location.assign(url);
}

Dans IE, il existe une méthode ClearAuthenticationCache qui élimine «ces entrailles trÚs profondes». Simple et élégant. Et pas de danse avec la page auxiliaire 401. Je ne sais pas si cette méthode fonctionne dans Edge. Probablement oui.

La construction document.execCommand renvoie true si la méthode existe et "a fonctionné". Ensuite, window.location.assign (url) redirige l'utilisateur pour entrer un nouveau nom d'utilisateur et mot de passe

Firefox (72.0.1)


Dans le cadre de notre tĂąche, c'est le navigateur le plus problĂ©matique. Pour lui, une solution complĂšte n'existe toujours pas. Depuis 15-20 ans, une demande pour le problĂšme indiquĂ© est suspendue dans le tracker de bug de l'Ă©quipe de ses dĂ©veloppeurs. Mais «les choses sont toujours là». Le maximum qui peut ĂȘtre atteint est la courbe razlogin.

Entrée:
Firefox ne rĂ©initialise pas le cache de mot de passe aprĂšs avoir reçu une rĂ©ponse 401 via XMLHttpRequest ou une demande de rĂ©cupĂ©ration. Uniquement via une demande rĂ©guliĂšre avec le login / mot de passe dans l'URL elle-mĂȘme. Autrement dit, quelque chose comme
http: // aucun: aucun@mysite.com/
Le code:

else if (/firefox|iceweasel|fxios/i.test(window.navigator.userAgent)) {
    url.username = 'none';
    url.password = 'none';
    window.location.assign(url);
}

AprÚs quoi l'utilisateur reçoit un formulaire de saisie de login / mot de passe, dans lequel tout ce que vous entrez, il apparaßtra encore et encore. Le fait est que les valeurs saisies ne remplaceront pas les valeurs de login / mot de passe spécifiées dans l'URL. Autrement dit, au lieu des valeurs saisies, un tas de rien: aucun n'ira au serveur à chaque fois. Et pour vous connecter sous un autre nom, l'utilisateur doit cliquer sur Annuler, aller sur la page de démarrage (http: //mysite.com/) et y entrer un nouveau login / mot de passe.

Courbé? Mais hélas, il n'y a pas d'autre solution

Google Chrome (79.0.3945.88)


Pour Chrome, la mĂ©thode de rĂ©cupĂ©ration fonctionne trĂšs bien. Mais XMLHttpRequest ne fonctionne pas ((((Le cache n'est pas rĂ©initialisĂ© et la journalisation ne se produit pas. De plus, j'ai essayĂ© de dĂ©finir le login / mot de passe Ă  la fois comme paramĂštres pour la mĂ©thode ouverte et pour dĂ©finir l'en-tĂȘte.

else if (/chrome/i.test(window.navigator.userAgent)) {
    fetch(url401, {
      credentials: 'include',
      headers: {
        'Authorization': 'Basic ' + btoa('none:none'),
        'X-Requested-With': 'XMLHttpRequest'
      }
    }).then(() => {
      window.location.assign(url);
    }).catch(err => console.error(err));
}

Nous faisons une demande de récupération à la page 401 avec un nom d'utilisateur / mot de passe manifestement incorrect, nous obtenons une réponse 401 du serveur, le navigateur vide son cache.

IMPORTANT! Le serveur ne doit PAS renvoyer un en - tĂȘte WWW-Authenticate . Sinon, le navigateur prendra le contrĂŽle et les redirections Ă  partir de la page 401 ne se produiront jamais. Par convention, le serveur ne doit pas retourner cet en-tĂȘte si X-Requested-With: XMLHttpRequest est spĂ©cifiĂ© dans la demande . Par consĂ©quent, l'en - tĂȘte X-Requested-With a Ă©tĂ© ajoutĂ© Ă  la demande .

Safari (12)


Pour Safari, la situation est exactement le contraire: XMLHttpRequest fonctionne, mais la récupération ne fonctionne pas

else {
    const xhr = new XMLHttpRequest();
    xhr.open("GET", url401, true, 'none', 'none');
    xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
    xhr.onerror = function(err) {
      console.error(err);
    };
    xhr.onload = function () {
      window.location.assign(url);
    };
    xhr.send()
}

Les actions sont les mĂȘmes que dans Chrome, uniquement via XMLHttpRequest

Devrait fonctionner pour les versions de Safari 6+. Les versions antérieures avaient leurs propres bogues. En particulier, par exemple, dans les versions à partir de 5.1, à chaque redirection, le navigateur a de nouveau demandé l'autorisation, ce qui explique pourquoi l'autorisation avec redirection vers la page finale ne fonctionnait pas en principe. Et dans les versions antérieures à 5.0, la journalisation ne fonctionnait pas.

All Articles