web-dev-qa-db-fra.com

Authentification HTTP Déconnexion via PHP

Quel est le moyen correct de se déconnecter du dossier protégé par authentification HTTP?

Il existe des solutions de contournement qui peuvent y parvenir, mais elles sont potentiellement dangereuses car elles peuvent être buggées ou ne pas fonctionner dans certaines situations/navigateurs. C'est pourquoi je cherche une solution correcte et propre.

147
Josef Sábl

Mu. Il n'existe pas de moyen correct, pas même cohérent d'un navigateur à l'autre.

C'est un problème qui provient de la spécification HTTP (section 15.6):

Les clients HTTP existants et les agents d'utilisateurs conservent généralement l'authentification information indéfiniment. HTTP/1.1. ne fournit pas de méthode pour un serveur pour demander aux clients de supprimer ces informations d'identification mises en cache.

D'autre part, la section 10.4.2 dit:

Si la demande contient déjà des informations d’autorisation, le code 401 la réponse indique que l'autorisation a été refusée pour ces personnes lettres de créance. Si la réponse 401 contient le même défi que le réponse précédente, et l'agent utilisateur a déjà tenté authentification au moins une fois, l’utilisateur DEVRAIT alors être présenté le entité qui a été donnée dans la réponse, puisque cette entité pourrait inclure des informations de diagnostic pertinentes.

En d'autres termes, vous pourrez peut-être afficher à nouveau la boîte de connexion (sous la forme @Karsten dit), mais le navigateur n'a pas à honorer votre demande - ne dépend donc pas sur cette (mauvaise) fonctionnalité trop.

102
Piskvor

Méthode qui fonctionne bien dans Safari. Fonctionne également dans Firefox et Opera, mais avec un avertissement.

Location: http://[email protected]/

Cela indique au navigateur d'ouvrir une URL avec un nouveau nom d'utilisateur, en remplaçant le précédent.

57
Kornel

La réponse simple est que vous ne pouvez pas vous déconnecter de manière fiable de l'authentification http.

La réponse longue:
Http-auth (comme le reste de la spécification HTTP) est censé être sans état. Donc, être "connecté" ou "déconnecté" n'est pas vraiment un concept qui a du sens. La meilleure façon de le voir est de demander, pour chaque requête HTTP (et rappelez-vous, le chargement d'une page est généralement constitué de plusieurs requêtes), "êtes-vous autorisé à faire ce que vous demandez?". Le serveur voit chaque demande comme nouvelle et sans relation avec les demandes précédentes.

Les navigateurs ont choisi de se rappeler les informations d'identification que vous leur avez données lors du premier 401 et de les renvoyer sans l'autorisation explicite de l'utilisateur pour les demandes suivantes. Il s’agit d’une tentative visant à donner à l’utilisateur le modèle "connecté/déconnecté" auquel il s’attend, mais c’est purement un kludge. C'est le navigateur qui simule cette persistance d'état. Le serveur Web l'ignore complètement.

Par conséquent, la "déconnexion", dans le contexte de http-auth, est une simulation fournie par le navigateur et ne relève donc pas de l'autorité du serveur.

Oui, il y a des kludges. Mais ils brisent le repos (si cela vous est précieux) et ils ne sont pas fiables.

Si vous avez absolument besoin d'un modèle connecté/déconnecté pour l'authentification de votre site, le meilleur choix est un cookie de suivi, avec la persistance de l'état stocké sur le serveur (mysql, sqlite, flatfile, etc.). Cela nécessitera que toutes les demandes soient évaluées, par exemple avec PHP.

43
Jonathan Hanson

Solution de contournement

Vous pouvez le faire en utilisant Javascript:

<html><head>
<script type="text/javascript">
function logout() {
    var xmlhttp;
    if (window.XMLHttpRequest) {
          xmlhttp = new XMLHttpRequest();
    }
    // code for IE
    else if (window.ActiveXObject) {
      xmlhttp=new ActiveXObject("Microsoft.XMLHTTP");
    }
    if (window.ActiveXObject) {
      // IE clear HTTP Authentication
      document.execCommand("ClearAuthenticationCache");
      window.location.href='/where/to/redirect';
    } else {
        xmlhttp.open("GET", '/path/that/will/return/200/OK', true, "logout", "logout");
        xmlhttp.send("");
        xmlhttp.onreadystatechange = function() {
            if (xmlhttp.readyState == 4) {window.location.href='/where/to/redirect';}
        }


    }


    return false;
}
</script>
</head>
<body>
<a href="#" onclick="logout();">Log out</a>
</body>
</html>

Ce qui est fait ci-dessus est:

  • pour IE - effacez le cache d'authentification et redirigez quelque part 

  • pour les autres navigateurs - envoie un XMLHttpRequest en arrière-plan avec le nom de connexion et le mot de passe de "déconnexion". Nous devons l’envoyer à un chemin qui retournera 200 OK à cette demande (c’est-à-dire qu’elle ne devrait pas nécessiter une authentification HTTP).

Remplacez '/where/to/redirect' par un chemin vers lequel rediriger après la déconnexion et remplacez '/path/that/will/return/200/OK' par un chemin sur votre site qui renverra 200 OK.

26
Anton Mochalin

Solution de contournement (pas une solution propre, agréable (ou même fonctionnelle! Voir les commentaires)):

Désactiver ses informations d'identification une fois.

Vous pouvez déplacer votre logique d'authentification HTTP vers PHP en envoyant les en-têtes appropriés (s'ils ne sont pas connectés):

Header('WWW-Authenticate: Basic realm="protected area"');
Header('HTTP/1.0 401 Unauthorized');

Et en analysant l'entrée avec:

$_SERVER['PHP_AUTH_USER'] // httpauth-user
$_SERVER['PHP_AUTH_PW']   // httpauth-password

Donc, désactiver ses identifiants une fois devrait être trivial.

13
Karsten

Déconnexion de HTTP Basic Auth en deux étapes

Disons que j’ai un domaine d’authentification HTTP basique nommé «Mot de passe protégé» et que Bob est connecté. Pour me déconnecter, je crée 2 demandes AJAX:

  1. Accédez au script/logout_step1. Il ajoute un utilisateur temporaire aléatoire à .htusers et répond avec son identifiant et son mot de passe.
  2. Script d'accès/logout_step2 authentifié avec le nom d'utilisateur et le mot de passe de l'utilisateur temporaire . Le script supprime l'utilisateur temporaire et ajoute cet en-tête à la réponse: WWW-Authenticate: Basic realm="Password protected"

À ce stade, le navigateur a oublié les références de Bob.

7
Vlad GURDIGA

Ma solution au problème est la suivante. Vous pouvez trouver la fonction http_digest_parse, $realm et $users dans le deuxième exemple de cette page: http://php.net/manual/fr/features.http-auth.php

session_start();

function LogOut() {
  session_destroy();
  session_unset($_SESSION['session_id']);
  session_unset($_SESSION['logged']);

  header("Location: /", TRUE, 301);   
}

function Login(){

  global $realm;

  if (empty($_SESSION['session_id'])) {
    session_regenerate_id();
    $_SESSION['session_id'] = session_id();
  }

  if (!IsAuthenticated()) {  
    header('HTTP/1.1 401 Unauthorized');
    header('WWW-Authenticate: Digest realm="'.$realm.
   '",qop="auth",nonce="'.$_SESSION['session_id'].'",opaque="'.md5($realm).'"');
    $_SESSION['logged'] = False;
    die('Access denied.');
  }
  $_SESSION['logged'] = True;  
}

function IsAuthenticated(){
  global $realm;
  global $users;


  if  (empty($_SERVER['PHP_AUTH_DIGEST']))
      return False;

  // check PHP_AUTH_DIGEST
  if (!($data = http_digest_parse($_SERVER['PHP_AUTH_DIGEST'])) ||
     !isset($users[$data['username']]))
     return False;// invalid username


  $A1 = md5($data['username'] . ':' . $realm . ':' . $users[$data['username']]);
  $A2 = md5($_SERVER['REQUEST_METHOD'].':'.$data['uri']);

  // Give session id instead of data['nonce']
  $valid_response =   md5($A1.':'.$_SESSION['session_id'].':'.$data['nc'].':'.$data['cnonce'].':'.$data['qop'].':'.$A2);

  if ($data['response'] != $valid_response)
    return False;

  return True;
}
7
Pie86

En règle générale, une fois qu'un navigateur a demandé à l'utilisateur des informations d'identification et les a fournies à un site Web particulier, il continue à le faire sans autre invite. Contrairement aux différentes manières dont vous pouvez effacer les cookies côté client, je ne connais pas de façon similaire de demander au navigateur d'oublier les informations d'authentification fournies.

4
Greg Hewgill

Ce n'est peut-être pas la solution recherchée, mais je l'ai résolue de la manière suivante ... J'ai deux scripts pour le processus de déconnexion.

logout.php

<?php
header("Location: http://[email protected]/log.php");
?>

log.php

<?php
header("location: https://google.com");
?>

De cette façon, je ne reçois pas d'avertissement et ma session est terminée

2
Kevin

Trac - par défaut - utilise également l'authentification HTTP. La déconnexion ne fonctionne pas et ne peut pas être réparée:

  • Ceci est un problème avec le schéma d'authentification HTTP lui-même et nous ne pouvons rien faire dans Trac pour le réparer correctement.
  • Il n'existe actuellement aucune solution de contournement (JavaScript ou autre) compatible avec tous les principaux navigateurs.

De:http://trac.edgewall.org/ticket/791#comment:103

On dirait qu'il n'y a pas de réponse valable à la question, cette question a été rapportée il y a sept ans et cela a du sens: HTTP est sans état. Une demande est effectuée avec les informations d'authentification ou non. Mais c'est le client qui envoie la demande, pas le serveur qui la reçoit. Le serveur peut seulement dire si une URI de requête a besoin d'une autorisation ou non.

2
hakre

J'avais besoin de réinitialiser l'autorisation .htaccess alors j'ai utilisé ceci:

<?php
if (!isset($_SERVER['PHP_AUTH_USER'])) {
    header('WWW-Authenticate: Basic realm="My Realm"');
    header('HTTP/1.0 401 Unauthorized');
    echo 'Text to send if user hits Cancel button';
    exit;
}
?>

Je l'ai trouvé ici: http://php.net/manual/en/features.http-auth.php

Allez comprendre.

Un certain nombre de solutions se trouvent sur cette page et il est même noté en bas: Lynx, ne supprime pas l’authentification comme les autres navigateurs;)

Je l'ai testé sur mes navigateurs installés et, une fois fermé, chaque navigateur semble devoir être réactivé régulièrement lors de la rentrée.

2
Dooley

Autant que je sache, il n’existe aucun moyen propre d’implémenter une fonction de "déconnexion" lors de l’utilisation de l’authentification htaccess (c'est-à-dire basée sur HTTP).

En effet, cette authentification utilise le code d'erreur HTTP "401" pour indiquer au navigateur que des informations d'identification sont requises. Le navigateur invite alors l'utilisateur à fournir les détails. À partir de ce moment, jusqu'à la fermeture du navigateur, les informations d'identification seront toujours envoyées sans autre invite.

1
Alnitak

La meilleure solution que j'ai trouvée jusqu'à présent est (c'est en quelque sorte un pseudo-code, le $isLoggedIn est une pseudo variable pour http auth):

Au moment de la "déconnexion", stockez simplement des informations dans la session en indiquant que l'utilisateur est réellement déconnecté.

function logout()
{
  //$isLoggedIn = false; //This does not work (point of this question)
  $_SESSION['logout'] = true;
}

À l'endroit où je vérifie l'authentification, je développe la condition:

function isLoggedIn()
{
  return $isLoggedIn && !$_SESSION['logout'];
}

La session étant un peu liée à l'état d'authentification http, l'utilisateur reste déconnecté tant qu'il laisse le navigateur ouvert et tant que l'authentification http persiste dans le navigateur.

1
Josef Sábl

Peut-être que je manque le point.

Le moyen le plus fiable que j'ai trouvé pour mettre fin à l'authentification HTTP consiste à fermer le navigateur et toutes les fenêtres du navigateur. Vous pouvez fermer une fenêtre de navigateur à l'aide de Javascript, mais je ne pense pas que vous puissiez fermer toutes les fenêtres de navigateur.

1
Toby Allen

Il y a beaucoup de réponses - complexes - complexes ici. Dans mon cas particulier, j'ai trouvé un correctif simple et clair pour la déconnexion. Je n'ai pas encore testé dans Edge . Sur ma page à laquelle je me suis connecté, j'ai placé un lien de déconnexion similaire à celui-ci:

<a href="https://MyDomainHere.net/logout.html">logout</a>

Et dans l'en-tête de cette page logout.html (qui est également protégée par le .htaccess), j'ai un rafraîchissement de page semblable à celui-ci:

<meta http-equiv="Refresh" content="0; url=https://logout:[email protected]/" />

Où vous laisseriez les mots "déconnexion" en place pour effacer le nom d'utilisateur et le mot de passe mis en cache pour le site.

J'admettrai que si plusieurs pages devaient pouvoir être directement connectées depuis le début, chacun de ces points d'entrée aurait besoin de sa propre page logout.html correspondante. Sinon, vous pouvez centraliser la déconnexion en introduisant une étape supplémentaire de contrôle d'accès dans le processus avant l'invite de connexion proprement dite, ce qui nécessite la saisie d'une phrase pour atteindre une destination de connexion.

0
johnwayne

Alors que les autres ont raison de dire qu'il est impossible de se déconnecter de l'authentification HTTP de base, il existe des moyens de mettre en œuvre l'authentification qui se comporte de manière similaire. Une solution évidente consiste à utiliser auth_memcookie . Si vous souhaitez réellement implémenter l'authentification HTTP de base (c.-à-d. Utiliser les boîtes de dialogue du navigateur pour vous connecter au lieu d'un formulaire HTTP), utilisez simplement ceci: définissez l'authentification sur un répertoire protégé .htaccess distinct contenant un script PHP qui redirige vers L'utilisateur est venu après la création de la session memcache. 

0
symcbean

Le seul moyen efficace que j'ai trouvé pour effacer les informations d'identification PHP_AUTH_DIGEST ou PHP_AUTH_USER AND PHP_AUTH_PW consiste à appeler l'en-tête HTTP/1.1 401 Unauthorized.

function clear_admin_access(){
    header('HTTP/1.1 401 Unauthorized');
    die('Admin access turned off');
}
0
CIRCLE