Каким способом верный выйти из папки, защищенной аутентификацией HTTP?
Существуют обходные пути, которые позволяют добиться этого, но они потенциально опасны, поскольку могут содержать ошибки или не работать в определенных ситуациях / браузерах. Поэтому ищу правильное и чистое решение.
Я не понимаю, почему это важно, но это оба случая: деактивация на основе внутренних условий в приложении, а также типичная кнопка выхода. Объясните пожалуйста, почему это важно, я отредактирую прямо в вопросе.
«Правильное и чистое решение» - это браузеры, имеющие собственную кнопку выхода из системы, при нажатии на которую браузер перестанет отправлять заголовки Auth ... Можно ли мечтать, верно?
На панели инструментов веб-разработчика есть такая «кнопка».
Что сказал Йозеф: панель инструментов веб-разработчика для Firefox -> Miscellaneous -> Clear Private Data -> HTTP Authentication






Обычно после того, как браузер запросил у пользователя учетные данные и предоставил их определенному веб-сайту, он продолжит делать это без дополнительных запросов. В отличие от различных способов очистки файлов cookie на стороне клиента, я не знаю аналогичного способа попросить браузер забыть предоставленные учетные данные для аутентификации.
Я считаю, что есть возможность удалять аутентифицированные сеансы, когда вы выбираете «Удалить личные данные» в Firefox.
Также расширение панели инструментов веб-разработчика для Firefox предлагает функцию удаления HTTP-аутентификации. Но об этом не может быть и речи, поскольку мы действительно не можем попросить наших пользователей загрузить расширения FF или запустить загадочные команды браузера :-)
Стандартный способ выхода Firefox из HTTP-аутентификации доступен в разделе «Инструменты»> «Очистить недавнюю историю ...» в виде флажка «Активный вход». Это не интуитивно понятно и не позволяет вам выйти только из одного домена, вы всегда выходите из каждой страницы.
AFAIK, нет чистого способа реализовать функцию «выхода из системы» при использовании аутентификации htaccess (то есть на основе HTTP).
Это связано с тем, что такая аутентификация использует код ошибки HTTP «401», чтобы сообщить браузеру, что требуются учетные данные, после чего браузер запрашивает подробности у пользователя. С этого момента, пока браузер не будет закрыт, он всегда будет отправлять учетные данные без дополнительных запросов.
Обходной путь (не чистое, красивое (или даже не работающее! См. Комментарии) решение):
Отключите его учетные данные один раз.
Вы можете перенести логику 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
Так что отключение его учетных данных один раз должно быть тривиальным.
Проблема с этим решением заключается в следующем: вы даете IE знать, что учетные данные не в порядке. Он отображает диалоговое окно входа в систему с пустыми полями (без отображения значений, хранящихся в диспетчере паролей). Но когда вы нажимаете кнопку «Отмена» и обновляете страницу, она отправляет сохраненные учетные данные, таким образом снова входя в систему.
Проголосовали против; Как прокомментировал Йозеф Соболь, это не решает проблему.
Mu. Не существует правильного пути, даже не согласованный во всех браузерах.
Это проблема, возникающая из Спецификация HTTP (раздел 15.6):
Existing HTTP clients and user agents typically retain authentication information indefinitely. HTTP/1.1. does not provide a method for a server to direct clients to discard these cached credentials.
С другой стороны, в разделе 10.4.2 говорится:
If the request already included Authorization credentials, then the 401 response indicates that authorization has been refused for those credentials. If the 401 response contains the same challenge as the prior response, and the user agent has already attempted authentication at least once, then the user SHOULD be presented the entity that was given in the response, since that entity might include relevant diagnostic information.
Другими словами, вы можете снова показать окно входа в систему (как говорит @Karsten), но браузер не обязан выполнять ваш запрос - так что не слишком полагайтесь на эту (неправильную) особенность.
Это ошибка в RFC. W3C лень исправлять. Очень грустно.
Как @Jonathan Hanson предложил ниже, вы можете использовать cookie отслеживания вместе с HTTP-аутентификацией. Для меня это лучший метод.
Метод, который отлично работает в Safari. Также работает в Firefox и Opera, но с предупреждением.
Location: http://[email protected]/
Это указывает браузеру открыть URL-адрес с новым именем пользователя, переопределяя предыдущее.
Согласно RFC 3986 (URI: Generic Syntax) раздел 3.2.1. (Информация для пользователя) использование user:password@host не рекомендуется. Использование только http://[email protected]/ в большинстве случаев не работает и должно работать.
Устарело, как правило, означает, что что-то не следует использовать, поскольку оно может или будет удалено в какой-то момент. Это может сработать для вас сейчас, но если вы его используете, будьте готовы к тому, что в какой-то момент он перестанет работать. Но хорошее решение.
@andho: да, это перенаправление. Вы должны использовать его со статусом 302.
По-видимому, простая ссылка на [email protected] также работает (ссылка "отключить" на этот URL) вместо перенаправления http в PHP ... Есть ли у этого недостатки?
Осторожно: отправка формы с использованием относительного пути может завершиться ошибкой, если это будет сделано после повторного входа в систему (вход в систему с приглашением выхода из системы), потому что адрес все равно будет [email protected]/path, а не yourserver.example.com/path/
+1 за рабочий хак, а это все, что нам действительно нужно! Когда вы тестируете 100 учетных записей пользователей своей организации, скажем, на VPN, это вроде как экономит вам время.
В Chrome 45 после выхода и повторного входа в систему всегда появляется подсказка ...
Лучшее решение, которое я нашел до сих пор (это своего рода псевдокод, $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 - это RESTful, сеансы - нет.
Мое решение проблемы следующее. Вы можете найти функции 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;
}
Простой ответ заключается в том, что вы не можете надежно выйти из http-аутентификации.
Длинный ответ:
Http-auth (как и остальная часть спецификации HTTP) не имеет состояния. Так что «войти в систему» или «выйти из системы» на самом деле не имеет смысла. Лучший способ увидеть это - спросить для каждого HTTP-запроса (и помните, что загрузка страницы обычно состоит из нескольких запросов): «Разрешено ли вам делать то, что вы запрашиваете?». Сервер видит каждый запрос как новый и не связанный с какими-либо предыдущими запросами.
Браузеры решили запомнить учетные данные, которые вы сообщаете им при первом запросе 401, и повторно отправлять их без явного разрешения пользователя на последующие запросы. Это попытка дать пользователю ожидаемую модель «авторизован / вышел из системы», но это просто путаница. Это браузер, моделирующий это постоянство состояния. Веб-сервер об этом совершенно не подозревает.
Таким образом, «выход из системы» в контексте http-auth - это чисто симуляция, предоставляемая браузером, и поэтому вне компетенции сервера.
Да, есть кладжи. Но они нарушают RESTfulness (если это важно для вас) и ненадежны.
Если вам абсолютно необходима модель авторизации / выхода из системы для аутентификации вашего сайта, лучшим вариантом является отслеживающий куки-файл с постоянством состояния, хранящимся на сервере каким-либо образом (mysql, sqlite, flatfile и т. д.). Это потребует обработки всех запросов, например, с помощью PHP.
В то время как другие правы, говоря, что невозможно выйти из базовой HTTP-аутентификации, существуют способы реализовать аутентификацию, которые аналогичным образом вести себя. Один очевидный призыв - использовать auth_memcookie. Если вы действительно хотите реализовать базовую HTTP-аутентификацию (т.е. использовать диалоги браузера для входа в систему вместо HTTP-формы), используя это, просто установите аутентификацию в отдельный защищенный каталог .htaccess, содержащий PHP-скрипт, который перенаправляет обратно туда, где пользователь пришел после создание сеанса memcache.
Trac - по умолчанию - также использует HTTP-аутентификацию. Выход из системы не работает и не может быть исправлен:
- This is an issue with the HTTP authentication scheme itself, and there's nothing we can do in Trac to fix it properly.
- There is currently no workaround (JavaScript or other) that works with all major browsers.
Из: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 не очищает аутентификацию, как другие браузеры;)
Я протестировал его на своих установленных браузерах, и после закрытия каждый браузер, похоже, постоянно требует повторной проверки при повторном входе.
Кажется, это не работает, я получаю текст отмены без всплывающего окна входа в систему.
Оказывается, отправка WWW-Authenticate вызвала проблему, автоматически избавившись от этого выхода из системы.
И наоборот, похоже, что НЕТ, отправляющий WWW-Authenticate при устранении проблемы в одном браузере (Chrome), заставляет другой браузер (Firefox) запоминать учетные данные и отправлять их при следующем запросе, что приводит к автоматическому повторному входу в систему! Ага!
Затем посмотрите на UA и сделайте одно или другое решение.
Допустим, у меня есть область HTTP Basic Auth с именем «Защищено паролем», и Боб вошел в систему. Чтобы выйти из системы, я делаю 2 запроса AJAX:
WWW-Authenticate: Basic realm = "Password protected".На этом этапе браузер забыл учетные данные Боба.
Ух ты! Это действительно заслуживает +1 за чистую изобретательность, даже если это совершенно безумная вещь.
Может, я упускаю суть.
Самый надежный способ завершить HTTP-аутентификацию, который я нашел, - это закрыть браузер и все окна браузера. Вы можете закрыть окно браузера с помощью Javascript, но я не думаю, что вы можете закрыть все окна браузера.
fyi некоторые браузеры не закрывают окно, если это единственная открытая вкладка, так что вопрос действительно спорный
В те давние годы у меня была задача реализовать кнопку выхода без закрытия окна :-) Но, может быть, они не стали бы останавливаться на том, чтобы «не закрывать окно». Но послушайте, это простое решение, которое может сработать для кого-то, и, честно говоря, я тогда его пропустил.
Обходной путь
Вы можете сделать это с помощью 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.
Это своего рода обходной путь для входа в систему как другого пользователя. Но это действительно работает и заслуживает большего уважения.
Думаю, это лучший ответ. Как указано в ответе это на аналогичный вопрос, рандомизация пароля может иметь некоторое преимущество.
Это было то, что я хотел - работало во всех браузерах без проблем. Сохранила унаследованную мной страницу выхода из системы. Я не обязательно хотел использовать JS (возможно, иррационально), но во всех других ответах были проблемы с кроссбраузерностью, и это сработало отлично.
Я не могу заставить эту работу работать так, как это объясняется. Когда я вернулся в защищенную область, браузер снова аутентифицируется, отправляя последние использованные действительные учетные данные в заголовке. Однако с небольшими изменениями у меня это сработало. Я изменил ответ 200 OK на заголовок с той же областью защищенной области, но принимал только пользователя / пароль «выход: выход». Таким образом, пользователь вошел в систему с этим пользователем, который «вышел из системы», и это тот пользователь, который пытается повторить попытку, когда он вернется в защищенную область. Защищенная область отклоняет этого пользователя / пропуск, поэтому пользователь может изменить свои учетные данные.
Это не работает, как объясняется. Протестировано в Chrome 40 и Firefox 35.
Отлично работает в Safari 9
\ o / \ o / Отличное решение !! Большое спасибо. Отлично работает в Chrome 70.0.3538, Internet Explorer 11.345 и Microsoft Edge. Самое главное ... он молчит, потому что в нем не отображается запрос браузера с просьбой указать имя пользователя / пароль. Хитрый трюк - использовать 4-й и 5-й параметры в xmlhttp.open ().
Возможно, это не то решение, которое искали, но я решил его вот так. У меня есть 2 сценария для выхода из системы.
logout.php
<?php
header("Location: http://[email protected]/log.php");
?>
log.php
<?php
header("location: https://google.com");
?>
Таким образом, я не получаю предупреждения, и мой сеанс завершается
Это было единственное решение, которое действительно сработало для меня! Протестировано в Firefox 37 и Chromium 41
Единственный эффективный способ, который я нашел, чтобы стереть учетные данные 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');
}
Здесь много замечательных - сложных - ответов. В моем конкретном случае я нашел чистое и простое решение для выхода из системы. Я еще не тестировал в 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.html. В противном случае вы можете централизовать выход из системы, добавив в процесс дополнительный шаг привратника перед фактическим запросом на вход, требующий ввода фразы для достижения места назначения входа.
при движении вперед это работает, он выходит из системы, но предыдущая история браузера все еще может восстановить сеанс.
Я обобщил свое решение в статье (https://www.hattonwebsolutions.co.uk/articles/how_to_logout_of_http_sessions), однако я использовал вызов ajax и 2 файла htaccess (как предлагается в этом вопросе: Как выйти из HTTP-аутентификации (htaccess), которая работает в Google Chrome?).
Короче - вы:
Это позволяет избежать появления вторичного всплывающего окна в папке выхода с запросом другого имени пользователя (что могло бы сбить с толку пользователей). В моей статье используется JQuery, но этого можно избежать.
Укажите цель выхода из системы. Должен ли это быть принудительный выход из системы (деактивация пользователя)? Простая функция выхода для пользователя? Что-нибудь еще?