Выход из HTTP-аутентификации через PHP

Каким способом верный выйти из папки, защищенной аутентификацией HTTP?

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

Укажите цель выхода из системы. Должен ли это быть принудительный выход из системы (деактивация пользователя)? Простая функция выхода для пользователя? Что-нибудь еще?

Karsten 16.01.2009 12:38

Я не понимаю, почему это важно, но это оба случая: деактивация на основе внутренних условий в приложении, а также типичная кнопка выхода. Объясните пожалуйста, почему это важно, я отредактирую прямо в вопросе.

Josef Sábl 16.01.2009 16:02

«Правильное и чистое решение» - это браузеры, имеющие собственную кнопку выхода из системы, при нажатии на которую браузер перестанет отправлять заголовки Auth ... Можно ли мечтать, верно?

DanMan 21.04.2012 21:18

На панели инструментов веб-разработчика есть такая «кнопка».

Josef Sábl 23.04.2012 11:37

Что сказал Йозеф: панель инструментов веб-разработчика для Firefox -> Miscellaneous -> Clear Private Data -> HTTP Authentication

Yarin 17.06.2012 02:15
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Symfony Station Communiqué - 7 июля 2023 г
Symfony Station Communiqué - 7 июля 2023 г
Это коммюнике первоначально появилось на Symfony Station .
Оживление вашего приложения Laravel: Понимание режима обслуживания
Оживление вашего приложения Laravel: Понимание режима обслуживания
Здравствуйте, разработчики! В сегодняшней статье мы рассмотрим важный аспект управления приложениями, который часто упускается из виду в суете...
Установка и настройка Nginx и PHP на Ubuntu-сервере
Установка и настройка Nginx и PHP на Ubuntu-сервере
В этот раз я сделаю руководство по установке и настройке nginx и php на Ubuntu OS.
Коллекции в Laravel более простым способом
Коллекции в Laravel более простым способом
Привет, читатели, сегодня мы узнаем о коллекциях. В Laravel коллекции - это способ манипулировать массивами и играть с массивами данных. Благодаря...
Как установить PHP на Mac
Как установить PHP на Mac
PHP - это популярный язык программирования, который используется для разработки веб-приложений. Если вы используете Mac и хотите разрабатывать...
151
5
115 062
18
Перейти к ответу Данный вопрос помечен как решенный

Ответы 18

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

Я считаю, что есть возможность удалять аутентифицированные сеансы, когда вы выбираете «Удалить личные данные» в Firefox.

Kristian J. 16.01.2009 12:02

Также расширение панели инструментов веб-разработчика для Firefox предлагает функцию удаления HTTP-аутентификации. Но об этом не может быть и речи, поскольку мы действительно не можем попросить наших пользователей загрузить расширения FF или запустить загадочные команды браузера :-)

Josef Sábl 04.03.2009 00:28

Стандартный способ выхода Firefox из HTTP-аутентификации доступен в разделе «Инструменты»> «Очистить недавнюю историю ...» в виде флажка «Активный вход». Это не интуитивно понятно и не позволяет вам выйти только из одного домена, вы всегда выходите из каждой страницы.

aef 28.04.2011 17:06

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 знать, что учетные данные не в порядке. Он отображает диалоговое окно входа в систему с пустыми полями (без отображения значений, хранящихся в диспетчере паролей). Но когда вы нажимаете кнопку «Отмена» и обновляете страницу, она отправляет сохраненные учетные данные, таким образом снова входя в систему.

Josef Sábl 19.01.2009 12:38

Проголосовали против; Как прокомментировал Йозеф Соболь, это не решает проблему.

Chris Wesseling 18.01.2012 13:31
Ответ принят как подходящий

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 лень исправлять. Очень грустно.

Erik Aronesty 08.12.2012 00:14

Как @Jonathan Hanson предложил ниже, вы можете использовать cookie отслеживания вместе с HTTP-аутентификацией. Для меня это лучший метод.

machineaddict 11.07.2013 12:13

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

Location: http://[email protected]/

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

Согласно RFC 3986 (URI: Generic Syntax) раздел 3.2.1. (Информация для пользователя) использование user:password@host не рекомендуется. Использование только http://[email protected]/ в большинстве случаев не работает и должно работать.

aef 28.04.2011 16:55

Устарело, как правило, означает, что что-то не следует использовать, поскольку оно может или будет удалено в какой-то момент. Это может сработать для вас сейчас, но если вы его используете, будьте готовы к тому, что в какой-то момент он перестанет работать. Но хорошее решение.

Night Owl 02.08.2011 09:22

@andho: да, это перенаправление. Вы должны использовать его со статусом 302.

Kornel 06.08.2011 15:16

По-видимому, простая ссылка на [email protected] также работает (ссылка "отключить" на этот URL) вместо перенаправления http в PHP ... Есть ли у этого недостатки?

moala 21.03.2012 17:40

Осторожно: отправка формы с использованием относительного пути может завершиться ошибкой, если это будет сделано после повторного входа в систему (вход в систему с приглашением выхода из системы), потому что адрес все равно будет [email protected]/path, а не yourserver.example.com/path/

Jason 12.04.2012 01:55
[email protected] работает без проблем в Chrome, но вызывает вопрос безопасности в Firefox. выйти из системы: [email protected] не заставит Firefox выдавать вопрос безопасности. Ни один из двух URL-адресов не работает в IE8: /
Thor A. Pedersen 26.06.2012 16:15

+1 за рабочий хак, а это все, что нам действительно нужно! Когда вы тестируете 100 учетных записей пользователей своей организации, скажем, на VPN, это вроде как экономит вам время.

Peter Host 05.08.2012 00:42

В Chrome 45 после выхода и повторного входа в систему всегда появляется подсказка ...

PJunior 12.09.2015 13:50

Лучшее решение, которое я нашел до сих пор (это своего рода псевдокод, $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, сеансы - нет.

deamon 12.11.2010 12:10

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

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

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

Michael 10.12.2014 21:27

Оказывается, отправка WWW-Authenticate вызвала проблему, автоматически избавившись от этого выхода из системы.

Michael 10.12.2014 21:32

И наоборот, похоже, что НЕТ, отправляющий WWW-Authenticate при устранении проблемы в одном браузере (Chrome), заставляет другой браузер (Firefox) запоминать учетные данные и отправлять их при следующем запросе, что приводит к автоматическому повторному входу в систему! Ага!

Michael 16.12.2014 20:02

Затем посмотрите на UA и сделайте одно или другое решение.

Lennart Rolland 21.11.2015 03:19

Выход из системы с базовой аутентификацией HTTP за два шага

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

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

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

Ух ты! Это действительно заслуживает +1 за чистую изобретательность, даже если это совершенно безумная вещь.

Andy Triggs 28.09.2012 17:28

Может, я упускаю суть.

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

fyi некоторые браузеры не закрывают окно, если это единственная открытая вкладка, так что вопрос действительно спорный

scape 01.07.2013 20:06

В те давние годы у меня была задача реализовать кнопку выхода без закрытия окна :-) Но, может быть, они не стали бы останавливаться на том, чтобы «не закрывать окно». Но послушайте, это простое решение, которое может сработать для кого-то, и, честно говоря, я тогда его пропустил.

Josef Sábl 19.10.2017 14:10

Обходной путь

Вы можете сделать это с помощью 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.

Это своего рода обходной путь для входа в систему как другого пользователя. Но это действительно работает и заслуживает большего уважения.

Charlie Rudenstål 15.04.2013 18:09

Думаю, это лучший ответ. Как указано в ответе это на аналогичный вопрос, рандомизация пароля может иметь некоторое преимущество.

zelanix 07.03.2014 00:52

Это было то, что я хотел - работало во всех браузерах без проблем. Сохранила унаследованную мной страницу выхода из системы. Я не обязательно хотел использовать JS (возможно, иррационально), но во всех других ответах были проблемы с кроссбраузерностью, и это сработало отлично.

dgig 16.05.2014 18:44

Я не могу заставить эту работу работать так, как это объясняется. Когда я вернулся в защищенную область, браузер снова аутентифицируется, отправляя последние использованные действительные учетные данные в заголовке. Однако с небольшими изменениями у меня это сработало. Я изменил ответ 200 OK на заголовок с той же областью защищенной области, но принимал только пользователя / пароль «выход: выход». Таким образом, пользователь вошел в систему с этим пользователем, который «вышел из системы», и это тот пользователь, который пытается повторить попытку, когда он вернется в защищенную область. Защищенная область отклоняет этого пользователя / пропуск, поэтому пользователь может изменить свои учетные данные.

jonaguera 17.02.2015 12:55

Это не работает, как объясняется. Протестировано в Chrome 40 и Firefox 35.

funforums 26.02.2015 18:16

Отлично работает в Safari 9

Matthieu 22.10.2015 15:45

\ o / \ o / Отличное решение !! Большое спасибо. Отлично работает в Chrome 70.0.3538, Internet Explorer 11.345 и Microsoft Edge. Самое главное ... он молчит, потому что в нем не отображается запрос браузера с просьбой указать имя пользователя / пароль. Хитрый трюк - использовать 4-й и 5-й параметры в xmlhttp.open ().

MMJ 12.12.2018 18:31

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

logout.php

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

log.php

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

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

Это было единственное решение, которое действительно сработало для меня! Протестировано в Firefox 37 и Chromium 41

zesaver 12.05.2015 01:25

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

при движении вперед это работает, он выходит из системы, но предыдущая история браузера все еще может восстановить сеанс.

johnwayne 18.10.2017 14:00

Я обобщил свое решение в статье (https://www.hattonwebsolutions.co.uk/articles/how_to_logout_of_http_sessions), однако я использовал вызов ajax и 2 файла htaccess (как предлагается в этом вопросе: Как выйти из HTTP-аутентификации (htaccess), которая работает в Google Chrome?).

Короче - вы:

  1. Создайте подпапку с файлом htaccess с тем же именем AuthName, но для этого потребуется другой пользователь.
  2. Отправьте запрос ajax на страницу (с неправильным именем пользователя) (что не удается), а затем инициируйте переадресацию тайм-аута на страницу, вышедшую из системы.

Это позволяет избежать появления вторичного всплывающего окна в папке выхода с запросом другого имени пользователя (что могло бы сбить с толку пользователей). В моей статье используется JQuery, но этого можно избежать.

Другие вопросы по теме