Отправитель аутентификации HTTP через PHP

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

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

Ответ 1

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

Это проблема, возникающая из Спецификация HTTP (раздел 15.6):

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

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

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

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

Ответ 2

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

Location: http://[email protected]/

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

Ответ 3

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

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

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

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

Да, есть клоды. Но они ломают RESTful-ness (если это значение для вас), и они ненадежны.

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

Ответ 4

Обход

Вы можете сделать это, используя 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 за кулисами с именем входа и паролем logout. Нам нужно отправить его на какой-то путь, который вернет 200 OK для этого запроса (т.е. Он не требует проверки подлинности HTTP).

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

Ответ 5

Обходное решение (не чистое, приятное (или даже работающее! см. комментарии)):

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

Вы можете переместить логику проверки подлинности 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

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

Ответ 6

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

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

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

Ответ 7

Мое решение проблемы заключается в следующем. Вы можете найти функции 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;
}

Ответ 8

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

Ответ 9

Trac - по умолчанию - использует HTTP-аутентификацию. Выход из системы не работает и не может быть исправлен:

  • Это проблема с самой схемой аутентификации HTTP, и мы ничего не можем сделать в Trac, чтобы исправить ее правильно.
  • В настоящее время нет обходного пути (JavaScript или другого), который работает со всеми основными браузерами.

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

Похоже, что нет никакого рабочего ответа на вопрос, этот вопрос был сообщен семь лет назад, и это имеет смысл: HTTP без гражданства. Либо запрос выполняется с учетными данными аутентификации, либо нет. Но дело в том, что клиент отправляет запрос, а не сервер, получающий его. Сервер может только сказать, требуется ли авторизация запроса URI или нет.

Ответ 10

Мне нужно было reset.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, не очищает auth, как другие браузеры;)

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

Ответ 11

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

logout.php

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

log.php

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

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

Ответ 12

AFAIK, нет чистого способа реализовать функцию "выхода" при использовании аутентификации htaccess (т.е. на основе HTTP).

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

Ответ 13

Лучшее решение, которое я нашел до сих пор (это своего рода псевдокод, $isLoggedIn является псевдо переменной для http auth):

Во время "выхода" просто сохраните некоторую информацию в сеансе, в которой говорится, что пользователь фактически вышел из системы.

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

В том месте, где я проверяю подлинность, я расширяю условие:

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

Сессия несколько связана с состоянием HTTP-аутентификации, поэтому пользователь остается включенным, пока он держит браузер открытым и до тех пор, пока в браузере сохраняется http-аутентификация.

Ответ 14

В то время как другие верны, говоря, что невозможно выйти из базовой HTTP-аутентификации, есть способы реализовать аутентификацию, которая ведет себя аналогично. Одним из очевидных подходов является использование auth_memcookie. Если вы действительно хотите реализовать базовую HTTP-аутентификацию (то есть использовать диалоговые окна браузера для входа в trather, чем HTTP-форму), используя это - просто установите аутентификацию в отдельный .htaccess защищенный каталог, содержащий PHP script, который перенаправляет обратно туда, где пользователь появился после создания сеанса memcache.

Ответ 15

Возможно, мне не хватает точки.

Самый надежный способ проверки подлинности HTTP - закрыть браузер и все окна браузера. Вы можете закрыть окно браузера с помощью Javascript, но я не думаю, что вы можете закрыть все окна браузера.

Ответ 16

Здесь много замечательных - сложных ответов. В моем конкретном случае я нашел чистое и простое исправление для выхода из системы. Мне еще предстоит проверить в Edge. На моей странице, на которой я вошел, я разместил ссылку для выхода из системы, похожую на это:

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

И в начале этой страницы logout.html(которая также защищена .htaccess) у меня есть обновление страницы, подобное этому:

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

Если вы оставите слова "logout" на месте, чтобы очистить имя пользователя и пароль, кэшированные для сайта.

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

Ответ 17

Единственный эффективный способ, с помощью которого я смог уничтожить учетные данные PHP_AUTH_DIGEST или PHP_AUTH_USER AND PHP_AUTH_PW, - это вызвать заголовок HTTP/1.1 401 Unauthorized.

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