HTTP-аутентификация в PHP
Возможно использовать функцию header() для
отправки сообщения "Authentication Required"
браузеру, заставив его показать окошко для ввода логина и пароля.
Как только пользователь заполнит логин и пароль, ссылка, содержащая
PHP-скрипт будет вызвана еще раз с
предопределенными переменными
PHP_AUTH_USER, PHP_AUTH_PW
и AUTH_TYPE, установленными в логин, пароль
и тип аутентификации соответственно. Эти предопределенные
переменные хранятся в массиве $_SERVER.
Поддерживаются оба типа: "Basic" и "Digest" (начиная с версии PHP 5.1.0). Подробнее
смотрите функцию header().
Пример фрагмента скрипта, который вынуждает клиента авторизоваться для просмотра страницы:
Пример #1 Пример Basic HTTP-аутентификации
<?php
if (!isset($_SERVER['PHP_AUTH_USER'])) {
header('WWW-Authenticate: Basic realm="My Realm"');
header('HTTP/1.0 401 Unauthorized');
echo 'Текст, отправляемый в том случае,
если пользователь нажал кнопку Cancel';
exit;
} else {
echo "<p>Hello {$_SERVER['PHP_AUTH_USER']}.</p>";
echo "<p>Вы ввели пароль {$_SERVER['PHP_AUTH_PW']}.</p>";
}
?>
Пример #2 Пример Digest HTTP-аутентификации
Это пример реализации простого скрипта Digest HTTP-аутентификации. За подробностями обращайтесь к » RFC 2617.
<?php
$realm = 'Запретная зона';
//user => password
$users = array('admin' => 'mypass', 'guest' => 'guest');
if (empty($_SERVER['PHP_AUTH_DIGEST'])) {
header('HTTP/1.1 401 Unauthorized');
header('WWW-Authenticate: Digest realm="'.$realm.
'",qop="auth",nonce="'.uniqid().'",opaque="'.md5($realm).'"');
die('Текст, отправляемый в том случае, если пользователь нажал кнопку Cancel');
}
// анализируем переменную PHP_AUTH_DIGEST
if (!($data = http_digest_parse($_SERVER['PHP_AUTH_DIGEST'])) ||
!isset($users[$data['username']]))
die('Неправильные данные!');
// генерируем корректный ответ
$A1 = md5($data['username'] . ':' . $realm . ':' . $users[$data['username']]);
$A2 = md5($_SERVER['REQUEST_METHOD'].':'.$data['uri']);
$valid_response = md5($A1.':'.$data['nonce'].':'.$data['nc'].':'.$data['cnonce'].':'.$data['qop'].':'.$A2);
if ($data['response'] != $valid_response)
die('Неправильные данные!');
// все хорошо, логин и пароль верны
echo 'Вы вошли как: ' . $data['username'];
// функция разбора заголовка http auth
function http_digest_parse($txt)
{
// защита от отсутствующих данных
$needed_parts = array('nonce'=>1, 'nc'=>1, 'cnonce'=>1, 'qop'=>1, 'username'=>1, 'uri'=>1, 'response'=>1);
$data = array();
$keys = implode('|', array_keys($needed_parts));
preg_match_all('@(' . $keys . ')=(?:([\'"])([^\2]+?)\2|([^\s,]+))@', $txt, $matches, PREG_SET_ORDER);
foreach ($matches as $m) {
$data[$m[1]] = $m[3] ? $m[3] : $m[4];
unset($needed_parts[$m[1]]);
}
return $needed_parts ? false : $data;
}
?>
Замечание: Замечание касательно совместимости
Будьте особенно внимательны при указании HTTP-заголовков. Для того, чтобы гарантировать максимальную совместимость с наибольшим количеством различных клиентов, слово "Basic" должно быть написано с большой буквы "B", регион (realm) должен быть взят в двойные (не одинарные!) кавычки, и ровно один пробел должен предшествовать коду 401 в заголовке HTTP/1.0 401. Параметры аутентификации должны разделяться запятыми, как это было показано в примере Digest аутентификации выше.
Вместо простого отображения на экране переменных PHP_AUTH_USER и PHP_AUTH_PW, вам, возможно, понадобится проверить их корректность. Используйте для этого запрос к базе данных или поиск пользователя в dbm-файле.
Вы можете пронаблюдать особенности работы браузера Internet Explorer.
Он очень требователен к параметру передаваемых заголовков. Трюк с указанием
заголовка WWW-Authenticate перед отправкой статуса
HTTP/1.0 401
пока что работает для него.
Замечание: Замечание касательно конфигурации
PHP использует указание директивы
AuthType
для указания того, используется внешняя аутентификация или нет.
Следует заметить, что все вышесказанное не предотвращает похищения паролей к страницам, требующим авторизацию, кем-либо, кто контролирует страницы без авторизации, расположенные на том же сервере.
И Netscape Navigator и Internet Explorer очищают кеш аутентификации текущего окна для заданного региона (realm) при получении от сервера статуса 401. Это может использоваться для реализации принудительного выхода пользователя и повторного отображения диалогового окна для ввода имени пользователя и пароля. Некоторые разработчики используют это для ограничения авторизации по времени или для предоставления кнопки "Выход".
Пример #3 Пример HTTP-аутентификации с принудительным вводом новой пары логин/пароль
<?php
function authenticate() {
header('WWW-Authenticate: Basic realm="Test Authentication System"');
header('HTTP/1.0 401 Unauthorized');
echo "Вы должны ввести корректный логин и пароль для получения доступа к ресурсу \n";
exit;
}
if (!isset($_SERVER['PHP_AUTH_USER']) ||
($_POST['SeenBefore'] == 1 && $_POST['OldAuth'] == $_SERVER['PHP_AUTH_USER'])) {
authenticate();
} else {
echo "<p>Добро пожаловать: " . htmlspecialchars($_SERVER['PHP_AUTH_USER']) . "<br />";
echo "Предыдущий логин: " . htmlspecialchars($_REQUEST['OldAuth']);
echo "<form action='' method='post'>\n";
echo "<input type='hidden' name='SeenBefore' value='1' />\n";
echo "<input type='hidden' name='OldAuth' value=\"" . htmlspecialchars($_SERVER['PHP_AUTH_USER']) . "\" />\n";
echo "<input type='submit' value='Авторизоваться повторно' />\n";
echo "</form></p>\n";
}
?>
Это поведение не регламентируется стандартами HTTP Basic
-аутентификации,
следовательно, вы не должны зависеть от этого. Тестирование браузера Lynx
показало, что Lynx
не очищает кеш авторизации при получении от сервера
статуса 401, и, нажав последовательно "Back", а затем "Forward" возможно
открыть такую страницу, при условии, что требуемые атрибуты авторизации не изменились.
Однако, пользователь может нажать клавишу '_'
для очистки кеша аутентификации.
Для того, чтобы добиться корректной работы HTTP-аутентификации в IIS сервере с
CGI версией PHP, вы должны отредактировать
конфигурационную настройку IIS под названием "Directory Security
".
Щелкните на надписи "Edit
" и установите опцию
"Anonymous Access
",
все остальные поля должны остаться неотмеченными.
Замечание: Замечание касательно IIS:
Для того, чтобы HTTP-аутентификация корректно работала в IIS, в конфигурации PHP опция cgi.rfc2616_headers должна быть установлена значением0
(значение по умолчанию).