Files
php-doc-ru/features/http-auth.xml
2021-04-24 10:56:17 +03:00

242 lines
12 KiB
XML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?xml version="1.0" encoding="utf-8"?>
<!-- EN-Revision: aab33d644359aba597e810e2fc0c0caa0d347c9c Maintainer: shein Status: ready -->
<!-- Reviewed: yes Maintainer: rjhdby -->
<!-- $Revision$ -->
<chapter xml:id="features.http-auth" xmlns="http://docbook.org/ns/docbook" xmlns:xlink="http://www.w3.org/1999/xlink">
<title>HTTP-аутентификация в PHP</title>
<simpara>
Возможно использовать функцию <function>header</function> для
отправки сообщения <literal>"Authentication Required"</literal>
браузеру, заставив его показать окошко для ввода логина и пароля.
Как только пользователь заполнит логин и пароль, ссылка, содержащая
PHP-скрипт будет вызвана ещё раз с
<link linkend="reserved.variables">предопределёнными переменными</link>
<varname>PHP_AUTH_USER</varname>, <varname>PHP_AUTH_PW</varname>
и <varname>AUTH_TYPE</varname>, установленными в логин, пароль
и тип аутентификации соответственно. Эти предопределённые
переменные хранятся в массиве <varname>$_SERVER</varname>.
Поддерживаются оба типа: "Basic" и "Digest". Подробнее
смотрите функцию <function>header</function>.
</simpara>
<para>
Пример фрагмента скрипта, который вынуждает клиента авторизоваться для
просмотра страницы:
</para>
<para>
<example>
<title>Пример Basic HTTP-аутентификации</title>
<programlisting role="php">
<![CDATA[
<?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>";
}
?>
]]>
</programlisting>
</example>
</para>
<para>
<example>
<title>Пример Digest HTTP-аутентификации</title>
<para>
Это пример реализации простого скрипта Digest HTTP-аутентификации.
За подробностями обращайтесь к <link
xlink:href="&url.rfc;2617">RFC 2617</link>.
</para>
<programlisting role="php">
<![CDATA[
<?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;
}
?>
]]>
</programlisting>
</example>
</para>
<note>
<title>Замечание касательно совместимости</title>
<para>
Будьте особенно внимательны при указании HTTP-заголовков. Для того, чтобы
гарантировать максимальную совместимость с наибольшим количеством
различных клиентов, слово "Basic" должно быть написано с большой буквы "B",
регион (realm) должен быть взят в двойные (не одинарные!) кавычки,
и ровно один пробел должен предшествовать коду <emphasis>401</emphasis> в заголовке
<emphasis>HTTP/1.0 401</emphasis>. Параметры аутентификации должны
разделяться запятыми, как это было показано в примере Digest
аутентификации выше.
</para>
</note>
<para>
Вместо простого отображения на экране переменных <varname>PHP_AUTH_USER</varname>
и <varname>PHP_AUTH_PW</varname>, вам, возможно, понадобится
проверить их корректность. Используйте для этого запрос к базе
данных или поиск пользователя в dbm-файле.
</para>
<para>
Вы можете пронаблюдать особенности работы браузера Internet Explorer.
Он очень требователен к параметру передаваемых заголовков. Трюк с указанием
заголовка <emphasis>WWW-Authenticate</emphasis> перед отправкой статуса
<literal>HTTP/1.0 401</literal> пока что работает для него.
</para>
<note>
<title>Замечание касательно конфигурации</title>
<para>
PHP использует указание директивы <literal>AuthType</literal> для
указания того, используется внешняя аутентификация или нет.
</para>
</note>
<simpara>
Следует заметить, что все вышесказанное не предотвращает похищения паролей к
страницам, требующим авторизацию, кем-либо, кто контролирует страницы без
авторизации, расположенные на том же сервере.
</simpara>
<simpara>
И Netscape Navigator и Internet Explorer очищают кеш аутентификации
текущего окна для заданного региона (realm) при получении от сервера статуса 401.
Это может использоваться для реализации принудительного выхода пользователя
и повторного отображения диалогового окна для ввода имени пользователя и
пароля. Некоторые разработчики используют это для ограничения авторизации по
времени или для предоставления кнопки "Выход".
</simpara>
<para>
<example>
<title>Пример HTTP-аутентификации с принудительным вводом новой пары логин/пароль</title>
<programlisting role="php">
<![CDATA[
<?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";
}
?>
]]>
</programlisting>
</example>
</para>
<simpara>
Это поведение не регламентируется стандартами <literal>HTTP Basic</literal>-аутентификации,
следовательно, вы не должны зависеть от этого. Тестирование браузера <literal>Lynx</literal>
показало, что <literal>Lynx</literal> не очищает кеш авторизации при получении от сервера
статуса 401, и, нажав последовательно "Back", а затем "Forward" возможно
открыть такую страницу, при условии, что требуемые атрибуты авторизации не изменились.
Однако, пользователь может нажать клавишу <literal>'_'</literal> для очистки кеша аутентификации.
</simpara>
<simpara>
Для того, чтобы добиться корректной работы HTTP-аутентификации в IIS сервере с
CGI версией PHP, вы должны отредактировать
конфигурационную настройку IIS под названием "<literal>Directory Security</literal>".
Щёлкните на надписи "<literal>Edit</literal>" и установите опцию
"<literal>Anonymous Access</literal>",
все остальные поля должны остаться неотмеченными.
</simpara>
<note>
<title>Замечание касательно IIS:</title>
<simpara>
Для того, чтобы HTTP-аутентификация корректно работала в IIS, в конфигурации
PHP-опция <link linkend="ini.cgi.rfc2616-headers">cgi.rfc2616_headers</link> должна
быть установлена значением <literal>0</literal> (значение по умолчанию).
</simpara>
</note>
</chapter>
<!-- Keep this comment at the end of the file
Local variables:
mode: sgml
sgml-omittag:t
sgml-shorttag:t
sgml-minimize-attributes:nil
sgml-always-quote-attributes:t
sgml-indent-step:1
sgml-indent-data:t
indent-tabs-mode:nil
sgml-parent-document:nil
sgml-default-dtd-file:"~/.phpdoc/manual.ced"
sgml-exposed-tags:nil
sgml-local-catalogs:nil
sgml-local-ecat-files:nil
End:
vim600: syn=xml fen fdm=syntax fdl=2 si
vim: et tw=78 syn=sgml
vi: ts=1 sw=1
-->