Каков правильный способ выхода из защищенной папки проверки подлинности HTTP?
Существуют обходные пути, которые могут достичь этого, но они потенциально опасны, потому что они могут быть ошибочными или не работать в определенных ситуациях / браузерах. Вот почему я ищу правильное и чистое решение.
Mu. Не существует правильного пути , даже не совместимого с браузерами.
Это проблема, вытекающая из спецификации HTTP (раздел 15.6):
Существующие HTTP-клиенты и пользовательские агенты обычно сохраняют информацию аутентификации на неопределенный срок. HTTP / 1.1. не предоставляет метод для сервера, на который клиенты могут отбрасывать эти кэшированные учетные данные.
С другой стороны, в разделе 10.4.2 говорится:
Если запрос уже включил учетные данные авторизации, то ответ 401 указывает, что для этих учетных данных было отказано в авторизации. Если ответ 401 содержит ту же задачу, что и предыдущий ответ, и пользовательский агент уже попытался выполнить аутентификацию хотя бы один раз, тогда пользователю ДОЛЖЕН быть представлен объект, который был указан в ответе, поскольку этот объект может содержать соответствующую диагностическую информацию.
Другими словами, вы можете снова показать окно входа в систему (как говорит @Karsten ), но браузер не должен выполнять ваш запрос – так что не слишком сильно зависеть от этой функции (mis).
Метод, который хорошо работает в Safari. Также работает в Firefox и Opera, но с предупреждением.
Location: http://logout@yourserver.example.com/
Это говорит браузеру, чтобы открыть URL с новым именем пользователя, переопределяя предыдущий.
Простой ответ заключается в том, что вы не можете надежно выйти из http-аутентификации.
Длинный ответ:
Http-auth (как и остальная часть спецификации HTTP) означает быть апатридом. Таким образом, «вход в систему» или «выход из системы» на самом деле не является концепцией, которая имеет смысл. Лучший способ увидеть это – спросить, для каждого HTTP-запроса (и помните, что загрузка страницы обычно представляет собой несколько запросов), «разрешено ли вам делать то, что вы запрашиваете?». Сервер видит каждый запрос как новый и не связан с любыми предыдущими запросами.
Браузеры решили запомнить учетные данные, которые вы им сообщаете в первых 401, и повторно отправить их без явного разрешения пользователя на последующие запросы. Это попытка предоставить пользователю «зарегистрированную / выведенную» модель, которую они ожидают, но это просто kludge. Это браузер, который имитирует это сохранение состояния. Веб-сервер полностью не знает об этом.
Таким образом, «выход из системы», в контексте http-auth – это просто симуляция, предоставляемая браузером, и, таким образом, вне полномочий сервера.
Да, есть клоды. Но они ломают RESTful-ness (если это ценно для вас), и они ненадежны.
Если для аутентификации вашего сайта вам абсолютно необходима модель входа в систему / выходила из системы, лучшим вариантом является файл cookie отслеживания с сохранением состояния, хранящегося на сервере каким-либо образом (mysql, sqlite, flatfile и т. Д.). Это потребует оценки всех запросов, например, с помощью PHP.
Временное решение
Вы можете сделать это, используя 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>
,<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.
Обходное решение (не чистое, приятное (или даже работающее! См. Комментарии) решение):
Отключите его учетные данные один раз.
Вы можете переместить логику проверки подлинности 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
Поэтому отключение его учетных данных один раз должно быть тривиальным.
Предположим, что у меня есть базовое пространство HTTP с именем «Защита паролем», и Боб вошел в систему. Чтобы выйти из системы, я делаю 2 запроса AJAX:
WWW-Authenticate: Basic realm="Password protected"
В этот момент браузер забыл учетные данные Боба.
Мое решение проблемы заключается в следующем. Вы можете найти функцию 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; }
Обычно, как только браузер запрашивает у пользователя учетные данные и отправляет их на определенный веб-сайт, он будет продолжать делать это без дальнейшего запроса. В отличие от различных способов очистки файлов cookie с клиентской стороны, я не знаю аналогичного способа попросить браузер забыть свои предоставленные аутентификационные данные.
Trac – по умолчанию – использует HTTP-аутентификацию. Выход из системы не работает и не может быть исправлен:
- Это проблема с самой схемой аутентификации HTTP, и мы ничего не можем сделать в Trac, чтобы исправить ее правильно.
- В настоящее время нет обходного пути (JavaScript или другого), который работает со всеми основными браузерами.
От: http://trac.edgewall.org/ticket/791#comment:103
Похоже, что нет никакого рабочего ответа на вопрос, этот вопрос был сообщен семь лет назад, и это имеет смысл: HTTP не имеет гражданства. Либо запрос выполняется с учетными данными аутентификации, либо нет. Но дело в том, что клиент отправляет запрос, а не сервер, получающий его. Сервер может только сказать, требуется ли URI запроса или нет.
Мне нужно было сбросить авторизацию .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, как другие браузеры;)
Я тестировал его на установленных браузерах и когда-то закрывался, каждый браузер, похоже, постоянно требует повторного запуска.
Это может быть не решение, которое нужно было искать, но я решил это так. У меня есть 2 скрипта для процесса выхода.
logout.php
<?php header("Location: http://.@domain.com/log.php"); ?>
log.php
<?php header("location: https://google.com"); ?>
Таким образом, я не получаю предупреждение, и моя сессия прекращается
AFAIK, нет чистого способа реализовать функцию «выхода» при использовании аутентификации htaccess (т.е. на основе HTTP).
Это связано с тем, что такая аутентификация использует код ошибки HTTP 401, чтобы сообщить браузеру, что учетные данные необходимы, и в этот момент браузер запрашивает у пользователя данные. С этого момента, пока браузер не будет закрыт, он всегда будет отправлять учетные данные без дальнейшего запроса.
Лучшее решение, которое я нашел до сих пор (это своего рода псевдокод, $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-проверка.
В то время как другие верны, говоря, что невозможно выйти из базовой HTTP-аутентификации, есть способы реализовать аутентификацию, которая ведет себя аналогичным образом. Одно очевидное обращение – использовать auth_memcookie . Если вы действительно хотите реализовать базовую HTTP-аутентификацию (т. Е. Использовать диалоговые окна браузера для входа в trather, чем HTTP-форму), используя это – просто установите аутентификацию в отдельный .htaccess защищенный каталог, содержащий скрипт PHP, который перенаправляет обратно туда, куда пришел пользователь создание сеанса memcache.
Может быть, мне не хватает смысла.
Самый надежный способ, которым я нашел завершение HTTP-аутентификации, – закрыть браузер и все окна браузера. Вы можете закрыть окно браузера с помощью Javascript, но я не думаю, что вы можете закрыть все окна браузера.
Здесь много замечательных ответов. В моем конкретном случае я нашел чистое и простое исправление для выхода из системы. Мне еще предстоит проверить в Edge. На моей странице, на которой я вошел, я разместил ссылку для выхода из системы, подобную этой:
<a href="https://MyDomainHere.net/logout.html">logout</a>
И в голове этой страницы logout.html (которая также защищена .htaccess), у меня есть обновление страницы, похожее на это:
<meta http-equiv="Refresh" content="0; url=https://logout:logout@MyDomainHere.net/" />
Если вы оставите слова «logout» на месте, чтобы очистить имя пользователя и пароль, кэшированные для сайта.
Я буду признавать, что если для нескольких страниц необходимо было напрямую войти в систему с самого начала, каждой из этих точек входа потребуется соответствующая страница logout.html. В противном случае вы можете централизовать выход из системы, введя дополнительный шаг гейткипера в процесс до фактического запроса на вход, требуя ввода фразы для достижения адресата входа.
Единственный эффективный способ, с помощью которого я смог уничтожить учетные данные PHP_AUTH_DIGEST
или PHP_AUTH_USER
и PHP_AUTH_PW
– это вызвать заголовок HTTP/1.1 401 Unauthorized
.
function clear_admin_access(){ header('HTTP/1.1 401 Unauthorized'); die('Admin access turned off'); }