HTTP-аутентификация в PHP

Возможно использовать функцию header() для отправки сообщения "Authentication Required" браузеру, заставив его показать окошко для ввода логина и пароля. Как только пользователь заполнит логин и пароль, ссылка, содержащая PHP-скрипт будет вызвана ещё раз с предопределёнными переменнымиPHP_AUTH_USER, PHP_AUTH_PW и AUTH_TYPE, установленными в логин, пароль и тип аутентификации соответственно. Эти предопределённые переменные хранятся в массиве $_SERVER. Поддерживаются только: "Basic" и "Digest". Подробнее смотрите функцию 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 (значение по умолчанию).

To Top