Авторизация средствами web-сервера
Для того, чтобы к файлам, находящимся в какой-либо директории, могли иметь доступ лишь определенные посетители, знающие два кодовых слова (логин и пароль), можно использовать встроенные в Web-сервер Apache средства ограничения доступа.
В конфигурационных файлах Apache есть специальная строчка - AccessFileName. Там указано имя файла, найдя который в той или иной папке, Apache выполнит по отношению к ней указания, содержащиеся в этом файле. По традиции этим именем является .htaccess, и именно таким оно установлено на всех серверах хостинга. В файл .htaccess можно поместить команды ограничения доступа к той папке, в которой это файл находится.
Выглядят эти команды так. Вначале указывается название защищенной зоны - AuthName. Именно это название будет впоследствии выводиться в запросе посетителю (рис.8.1).
AuthName "Private Zone"
AuthType Basic
В следующем параметре - AuthUserFile - указывается путь к файлу с логинами и паролями посетителей. Этот файл должен быть создан в особом формате, так как пароли в нем хранятся в зашифрованном виде. Для создания файлов с паролями применяются специальные программы - такую программу вы можете взять, например, в разделе технической поддержки компании Valuehost по адресу
http://support.valuehost.ru/bbs/files/69-htpasswd.exe. Запускать ее следует из командной строки в формате 69-htpasswd.exe -c имя_файла_паролей логин, а в открывшемся окне ввести пароль (используя только латинские буквы). Чтобы добавить новые логины и пароли в уже имеющийся файл, эту программу следует запускать без параметра -с.
По традиции файл с паролями посетителей принято называть .htpasswd. Обычно Apache настраивается так, что файлы с именами .htaccess и .htpasswd невозможно просмотреть через Web - при такой попытке будет выдаваться лишь сообщение о запрещении доступа. Однако выполнение такой настройки (для этого надо указать несколько параметров в httpd.conf - конфигурационном файле Apache) - целиком на совести администраторов web-сервера.
Обратите внимание, что путь к файлу паролей следует указывать абсолютный - то есть от корневого каталога сервера с указанием всего дерева каталогов. На серверах хостинга он обычно имеет вид /pub/home/имя аккаунта/..../имя файла паролей, а на вашем локальном компьютере зависит от местоположения web-сервера и его настроек, например, может выглядеть и как f:/www/exper/cov/.htpasswd.
AuthUserFile /pub/home/exper/cov/.htpasswd
require valid-user
То, что требуется указывать именно абсолютный путь к файлу с паролями, не должно вас удивлять. Это сделано для того, чтобы можно было использовать один и тот же файл паролей для организации ограничения доступа сразу к нескольким папкам и даже нескольким аккаунтам. В результате в том случае, если на сервер добавляется еще одна папка с защитой, то не требуется вновь раздавать посетителям новые логины и пароли для доступа уже к ней - достаточно прописать путь к уже имеющемуся файлу с паролями в файле .htaccess, и все указанные в нем пароли автоматически станут действительными и для входа в новосозданную папку.
Итак, пожелав "запаролить" доступ к ресурсам какой-либо папки, создайте файл с именем .htaccess с вышеуказанными параметрами.
Сделать это командой "Проводника" или "Нортона" вам не удастся, так как эти программы не допускают создание файлов без имени (а .htaccess они воспринимают именно как расширение без имени!), поэтому наберите соответствующий текст в какой-нибудь программе, позволяющей это совершить (например, ViewText Георгия Гуляева,
www.altailand.ru).
Создав файл .htaccess, загрузите программу для создания файла паролей и поработайте с нею. После этого загрузите оба файла на свой сайт: .htaccess - в закрываемую папку, а файл с паролями - в соответствии с прописанным в .htaccess путем к нему (рис.8.2).
Вот и все! Теперь при попытке запроса любого ресурса из защищенной папки (в том числе и картинок, включенных в другие страницы тэгом ) посетителю будет выдан стандартный запрос логина и пароля (рис.8.1). Если логин и пароль совпадают с хранящимися в файле паролей (по умолчанию есть три попытки ввода), то доступ разрешается, если нет - средствами web-сервера выводится соответствующее сообщение.
Доступ открывается "для определенного окна браузера и всех его дочерних окон". Иными словами, если посетитель однажды ввел правильные логин и пароль, то он, работая в одном и том же окне браузера, может не только свободно путешествовать по всем ресурсам в запароленной папке, но и, выйдя из нее, свободно вновь в нее войти. То же самое верно и для всех окон браузера, открытых из исходного с помощью команды "открыть в новом окне". А вот если пользователь откроет новое окно браузера и зайдет уже в нем в эту папку, то запрос на ввод логина и пароля появится вновь (разумеется, если страница не была взята из кэша браузера - в последнем случае достаточно ее обновить).
Использовать данный способ удается не всегда, - администрация сервера иной раз не позволяет это делать посетителям, да и программа для создания файла паролей не всегда под рукой. Однако средства PHP позволяют обойтись без применения файлов .htaccess.
Авторизация с помощью заголовка
В PHP есть команда Header - она позволяет отправить браузеру посетителя, запросившему страницу с содержащим эту команду сценарием, определенную служебную информацию - так называемый "заголовок". Существует довольно много вариантов заголовков (например, заголовок "Location: http://адрес" приведет к перенаправлению на указанный URL; то же самое, что и при использовании мета-тэга http-equiv с параметром "Refresh"), однако для авторизации нам потребуется заголовок "WWW-Authenticate".
Заголовок - это данные, передаваемые браузеру до передачи самой web-страницы, сообщающие ему некоторые параметры передаваемого файла или определенные команды. Список всех возможных заголовков, которые обязаны поддерживать современные браузеры, можно найти в спецификациях протокола HTTP - они есть, например, на сайте
www.w3.org. PHP-команда Header выполняет всего одно действие - она просто передает то, что указано в ее параметре, в браузер, запросивший страницу, на которой она находится, в качестве заголовка.
Следует помнить, что заголовок должен передаваться в браузер до любого другого вывода в него, за исключением установки cookie.
В том случае, если браузер получает заголовок "WWW-Authenticate", то он выдает посетителю стандартное окно для ввода логина и пароля, которое вы наверняка много раз видели (как на рис.8.1). Как только посетитель нажимает кнопку Ok этого окна, браузер вновь заходит на ту страницу, с которой этот заголовок был ему послан, но на этот раз уже передает сценарию на этой странице две переменные - то, что было введено в поля ввода логина и пароля. Web-сервер дает этим переменным имена $PHP_AUTH_USER и $PHP_AUTH_PW, и их становится можно использовать в остальных сценариях на странице как любые другие переменные - использовать в выражениях, сравнивать с каким-либо эталоном, присваивать им какие-либо другие значения, наконец.
Если посетитель нажимает кнопку Cancel в диалоговом окне запроса логина и пароля, то выполнение кода страницы просто продолжается со следующей строчки за командой Header. Никакие переменные странице не передаются.
Однако переменные $PHP_AUTH_USER и $PHP_AUTH_PW - не простые. Если они один раз были определены, то впоследствии они передаются всем web-страницам, которые загружаются в то же самое окно браузера, где произошла авторизация! Иными словами, если по каким-то причинам требуется проверять логин и пароль посетителя на каждой из страниц сайта (скажем, выводить разную информацию авторизованным и неавторизованным посетителям), то каждый раз запрашивать эти данные не нужно - достаточно использовать значения переменных $PHP_AUTH_USER и $PHP_AUTH_PW. Значения данных переменных теряются в случае закрытия окна браузера, в котором изначально произошла авторизация (а в другие окна они и не передаются). При выходе за пределы виртуального сервера, на котором произошла авторизация (обычно его границы совпадают с границами аккаунта), данные переменные перестают передаваться страницам, однако при повторном входе на исходный адрес вновь становятся доступными (это обеспечение безопасности - за пределами вашего виртуального сервера логины и пароли ваших посетителей никто узнать из их браузеров не сможет).
Кстати, при использовании предыдущего способа - средствами Apache - в переменные $PHP_AUTH_USER и $PHP_AUTH_PW тоже помещаются значения логина и пароля, введенные пользователем. В принципе вы можете найти им какое-нибудь применение.
К примеру, вспомним содержание седьмой главы, в которой рассматривалась программа для самостоятельной загрузки посетителями файлов на сайт. Помните, в чем была проблема - проверка пароля и сама загрузка файлов совершались сценарием на одной и той же странице, и в случае ошибки при вводе пароля посетитель все равно был вынужден ждать окончания загрузки файла на сайт, чтобы тот был сразу же оттуда удален? Так вот - используя данный способ авторизации (и предыдущий - средствами Apache - тоже), можно разделить авторизацию и закачку файлов, предоставив посетителю возможность вначале ввести логин с паролем, а только потом, если они правильные, выдать ему форму для закачки файла. Если добавить на страницу обработки закачанного файла краткую программу для проверки переменных $PHP_AUTH_USER и $PHP_AUTH_PW, то можно не бояться захода на страницу загрузки неавторизованных посетителей (скажем, по закладке или путем прямого набора ее адреса в браузере) - таковые будут отсеяны, а запросы легальных обработаны.
Ниже приводится сценарий, который запрашивает у пользователя логин и пароль, проверяет их по наличию в определенном файле, а затем выводит либо приглашение к загрузке файла, либо сообщение об отказе в авторизации.
Итак, начало сценария. Обратите внимание, что для того, чтобы он сработал, до команды Header в выдаваемый документ не должно ничего выводиться: ни результат выполнения команд PHP, ни простое содержимое страницы, - так уж воспринимают web-страницы браузеры. В частности, данный сценарий должен располагаться в самом начале страницы, и символы <?php должны быть на ней самыми первыми, перед ними не должно быть даже пробела.
<?php
Поскольку после выдачи окна авторизации браузер вновь вызывает web-страницу, передавая ей ав-торизационные данные, то можно проверить их еще до отправки браузеру заголовка WWW-Authenticate. В самом деле - если окно авторизации не выводилось вообще, то переменные $PHP_AUTH_USER $PHP_AUTH_PW будут пустыми (вернее, вообще не определены), а если выводилось - то в них окажется информация, введенная посетителем (то есть логин и пароль).
Наиболее простым вариантом будет указание логина и пароля в тексте самой программы авторизации - ведь все равно код на PHP, размещающийся на странице, посетители увидеть не смогут1. В этом случае команда проверки содержимого переменных $PHP_AUTH_USER и $PHP_AUTH_PW на соответствие указанным будет выглядеть как
if (($PHP_AUTH_USER!="login")||($PHP_AUTH_PW!= "parol"))
{
Дальше идет тот код, который выполняется в случае несоответствия содержимого переменных ука-занным в команде логину и паролю. В случае самой первой загрузки страницы он, естественно, тоже выполнится - переменные $PHP_AUTH_USER и $PHP_AUTH_PW в таком случае еще не будут определены.
Итак - выдаем окно авторизации, для чего посылаем браузеру соответствующий заголовок:
Header("WWW-Authenticate: Basic realm=\"Защищенная зона"\"");
Браузер, получив такое, выдаст посетителю окно (такое же, как на рис. 8.1) с запросом логина с паролем. После нажатия кнопки Ok страница будет загружена вновь и в том случае, если логин и пароль соответствовали указанным в ее тексте, будет выводиться остальной ее текст - тот, что последует за командой if, за ее закрывающей фигурной скобкой. Ну, а если логин и пароль будут введены неправильно, то окно авторизации выскочит вновь - и у посетителя появится еще один шанс правильно авторизоваться. И так до тех пор, пока не будут введены правильные логин и пароль.
Однако в выдаваемом окне есть еще кнопка "Отмена"! И в том случае, если посетитель нажмет ее, то код просто начнет выполняться дальше, со следующей после Header команды. Следовательно, в этот код и нужно вставить те команды, которые сообщают посетителю, так и не сумевшему ввести правильные логин с паролем, что он не может войти в защищенную зону. (Не забудьте, что все эти команды должны находиться в пределах блока оператора if - ведь нам надо, чтобы они выполнились только в случае нажатия кнопки "Отмена"!).
Выдадим браузеру заголовок, сообщающий об отказе в авторизации (требуется некоторым браузерам, а заодно и обнуляет переменные $PHP_AUTH_USER и $PHP_AUTH_PW):
Header("HTTP/1.0 401 Unauthorized");
...а затем - укажем тот текст, который должен быть выдан посетителю в случае отказа в авторизации - то есть нажатия им кнопки "Отмена" в диалоговом окне:
echo ("<p>Доступ закрыт!</p>");
(При желании вы можете сделать целую web-страницу, на которой подробно рассказать, например, как можно достать правильные логин с паролем, и вставлять ее текст сюда в случае отказа в авторизации с помощью команды include:
include ("noauth.php");
Например, так стоит сделать, если код этой страницы весьма большой или одна такая страница будет использоваться для нескольких мест авторизации.)
И, наконец, завершим работу с текущей страницей - нам ведь не нужно выполнять тот код, что дальше; он ведь должен быть доступен только авторизованным посетителям. Для выхода используем комаду exit:
exit;
}
Она полностью прекращает как вывод web-страницы посетителю, так и выполнение какого-либо кода.
Вот, собственно, и все:
?>
Для наглядности - все строчки кода вместе:
<?php
if (($PHP_AUTH_USER!="login")||($PHP_AUTH_PW!= "parol"))
{
Header("WWW-Authenticate: Basic realm=\"Защищенная зона"\"");
Header("HTTP/1.0 401 Unauthorized");
...текст страницы, выдающейся посетителю в случае нажатия им кнопки "Отмена"...
exit;
}
?>
Указание логина и пароля в самом тексте PHP-сценария - простой, но не очень удобный способ их хранения. В самом деле - если вы планируете предоставить доступ нескольким посетителям, то вам придется давать им одну и ту же пару логина и пароля. Это чревато тем, что при необходимости отказать кому-нибудь из них в доступе придется менять пароль, о чем придется сообщать всем остальным.
Ниже приводится небольшой код, реализующий проверку содержимого авторизационных переменных на совпадение с какой-нибудь парой "логин-пароль" из специального файла паролей.
Допустим, файл, содержащий логины и пароли, располагается в папке passw и называется passwr, а формат его прост - запись типа "логин пароль" (через пробел) на каждой строчке (см.рис.8.3). Для того, чтобы этот файл нельзя было загрузить через web-интерфейс, просто набрав его имя (и тем самым получив на экран все его содержимое), можете сделать это имя как можно более длинным и заковыристым (все равно оно фигурирует только в программном коде, то есть из Сети его узнать будет никак нельзя), а можете просто запретить чтение данного файла из Web, соответственно установив его атрибуты, например, в 770 (в CuteFTP это делается пунктом CHMOD из контекстного меню файла, рис.8.4).
Еще запретить чтение содержимого директорий из Web можно, указав в файле настроек web-сервера Apache (именующемся httpd.conf) в разделе описания соответствующего виртуального сервера параметр Location (например, deny from all - в три строки), однако доступ к файлу настроек web-сервера есть не всегда.