Выход из аутентификации HTTP через PHP - PullRequest
148 голосов
/ 16 января 2009

Каков правильный способ выхода из защищенной папки HTTP-аутентификации?

Есть обходные пути, которые могут достичь этого, но они потенциально опасны, потому что они могут содержать ошибки или не работать в определенных ситуациях / браузерах. Вот почему я ищу правильное и чистое решение.

Ответы [ 17 ]

102 голосов
/ 16 января 2009

Mu. Не существует правильного способа , даже не тот, который совместим во всех браузерах.

Эта проблема возникает из спецификации HTTP (раздел 15.6):

Существующие клиенты HTTP и пользовательские агенты обычно сохраняют аутентификацию информация до бесконечности. HTTP / 1.1. не предоставляет метод для сервер для направления клиентов на удаление этих кэшированных учетных данных.

С другой стороны, в разделе 10.4.2 написано:

Если в запрос уже включены учетные данные авторизации, то 401 ответ указывает на то, что авторизация была отклонена полномочия. Если ответ 401 содержит ту же проблему, что и предыдущий ответ, и пользовательский агент уже попытался аутентификации хотя бы один раз, тогда пользователю СЛЕДУЕТ представить объект, который был указан в ответе, так как этот объект может включите соответствующую диагностическую информацию.

Другими словами, вы можете снова отобразить окно входа в систему (как говорит @ Karsten ), , но браузер не должен выполнять ваш запрос - так что не слишком зависите от этой (неправильной) функции.

58 голосов
/ 22 января 2009

Метод, который хорошо работает в Safari. Также работает в Firefox и Opera, но с предупреждением.

Location: http://logout@yourserver.example.com/

Это говорит браузеру открыть URL с новым именем пользователя, переопределяя предыдущее.

45 голосов
/ 11 апреля 2010

Простой ответ заключается в том, что вы не можете надежно выйти из http-аутентификации.

Длинный ответ:
Http-auth (как и остальная часть спецификации HTTP) предназначен для сохранения состояния. Таким образом, «войти» или «выйти» на самом деле не имеет смысла. Лучший способ убедиться в этом - спросить для каждого HTTP-запроса (и помните, что загрузка страницы обычно состоит из нескольких запросов): «Вам разрешено делать то, что вы запрашиваете?». Сервер видит каждый запрос как новый и не связанный с любыми предыдущими запросами.

Браузеры решили запомнить учетные данные, которые вы сообщаете им в первые 401, и повторно отправлять их без явного разрешения пользователя на последующие запросы. Это попытка дать пользователю ожидаемую модель «вошел / вышел», но это просто помеха. Это браузер , который имитирует это постоянство состояния. Веб-сервер не знает об этом.

Таким образом, «выход из системы» в контексте http-auth является чисто симуляцией, предоставляемой браузером, и поэтому находится вне полномочий сервера.

Да, есть кладжи. Но они нарушают RESTful-ность (если это имеет ценность для вас), и они ненадежны.

Если вам абсолютно необходима модель входа в систему / выхода из нее для проверки подлинности вашего сайта, лучшим вариантом будет файл cookie для отслеживания с сохранением состояния на сервере каким-либо образом (mysql, sqlite, flatfile и т. Д.) , Это потребует оценки всех запросов, например, с помощью PHP.

26 голосов
/ 13 октября 2012

Обход

Вы можете сделать это, используя 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>

Что сделано выше:

  • для IE - просто очистите кэш аутентификации и перенаправьте куда-нибудь

  • для других браузеров - отправить запрос XMLHttpRequest за кулисами с логином и паролем для выхода из системы. Нам нужно отправить его по какому-то пути, который вернет 200 OK на этот запрос (то есть он не должен требовать HTTP-аутентификации).

Замените '/where/to/redirect' на какой-то путь для перенаправления после выхода из системы и замените '/path/that/will/return/200/OK' на какой-нибудь путь на своем сайте, который вернет 200 OK.

13 голосов
/ 16 января 2009

Обходной путь (не чистое, хорошее (или даже работающее! См. Комментарии) решение):

Отключить его учетные данные один раз.

Вы можете переместить свою логику HTTP-аутентификации в PHP, отправив соответствующие заголовки (если не вошли в систему):

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

И синтаксический анализ ввода с помощью:

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

Так что отключение его учетных данных один раз должно быть тривиальным.

7 голосов
/ 24 августа 2012

Выйти из HTTP Basic Auth в два этапа

Допустим, у меня есть область HTTP Basic Auth с именем «Защищено паролем», и Боб вошел в систему. Чтобы выйти, я делаю 2 запроса AJAX:

  1. Сценарий доступа / logout_step1. Он добавляет случайного временного пользователя в .htusers и отвечает его логином и паролем.
  2. Сценарий доступа / logout_step2 , аутентифицированный с использованием временного имени пользователя и пароля . Скрипт удаляет временного пользователя и добавляет этот заголовок в ответ: WWW-Authenticate: Basic realm="Password protected"

В этот момент браузер забыл учетные данные Боба.

7 голосов
/ 13 февраля 2010

Мое решение проблемы заключается в следующем. Вы можете найти функции http_digest_parse, $realm и $users во втором примере этой страницы: http://php.net/manual/en/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;
}
4 голосов
/ 16 января 2009

Как правило, когда браузер запрашивает учетные данные у пользователя и передает их на определенный веб-сайт, он будет продолжать делать это без дальнейших запросов. В отличие от различных способов очистки файлов cookie на стороне клиента, я не знаю аналогичного способа попросить браузер забыть предоставленные учетные данные для аутентификации.

2 голосов
/ 02 марта 2015

Возможно, это не то решение, которое искали, но я решил это следующим образом. у меня есть 2 сценария для выхода из системы.

logout.php

<?php
header("Location: http://.@domain.com/log.php");
?>

log.php

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

Таким образом, я не получаю предупреждение, и моя сессия прекращается

2 голосов
/ 07 декабря 2011

Мне нужно было сбросить авторизацию .htaccess, поэтому я использовал это:

<?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;
}
?>

Нашел здесь: http://php.net/manual/en/features.http-auth.php

Иди на цифру.

На этой странице находится несколько решений, и даже внизу: Lynx, не очищает аутентификацию, как в других браузерах;)

Я протестировал его в установленных браузерах и, закрыв его, кажется, что каждый браузер постоянно требует повторного входа.

...