Если вы новичок в Cake PHP?, вам настоятельно рекомендуется копировать код и вставлять в свое приложение для использования. Если нет: эта глава – обсуждение ядра Cake, а не безопасности приложений. Я сомневаюсь, что мы будем обсуждать очевидные засады безопасности, главная цель этого примера – показать как работает ядро Cake, и позволить вам создавать пуленепробиваемые приложения.
В Cake есть контроль доступа через втроенный движок ACL, но как насчет аутентификации пользователей? Как насчет этого?
Что ж, на данный момент, мы установили, что система аутентификации пльзователей изменяется от приложения к приложению. Некоторые люят хешированные пароли, другие, LDAP (Облегченный протокол доступа к кталогам) – и почти все приложения содержат модели User, которые незначительно отличаются. Теперь мы оставляем это на вас. Изменится ли это? Мы не уверены пока. Сейчас, мы думаем, что большие накладные расходы при встаивании этого в фреймворк того не стоят, потому что создание собственной системы аутентификации пользователей с Cake достаточно просто.
Вам нужно всего три вещи:
В этом примере, мы создадим простую систему аутентификации пользователей для системы управления клиентами. Это вымышленное приложение скорее всего будет использоваться в офисе, чтобы следить за контактной информацией и соответсвенными заметками клиентов. Вся функциональность системы будет размещена за нашей системой аутентификации пользователей, кроме нескольких отображений, которые будут показывать только имена и титулы клиентов, сохраненные в системе.
Мы начнем с того, что покажем вам как проверить пользователей, которые пытаются получить доступ к системе. Информация об аутентифицированном пользователе будет храниться в сессии PHP, используя компонент сессий. Когда у нас есть информация пользователя в сессии, мы поместим проверки в приложение, чтобы убедится, что пользователь не пытается добраться до мест, куда ему «не нужно» добираться.
На заметку – аутентификация это не то же самое что и контроль доступа. Все что нам нужно в этом примере это являются ли пользователи теми, кем себя заявляют, и дать им основной доступ к частям приложения. Мы будем делать заметки где можно разместить ACL, но пока, давайте сфокусируемся на простой аутентификации пользователей.
Я также должен отметить, что этот пример не претендует на звание какого-то букваря в безопасности приложения. Мы просто хотим дать вам достаточно, чтобы вы могли создать защищенные приложения самостоятельно.
Сначала нам нужен способ хранить информацию о пользователях, пытающихся получить доступ к нашей системе управления клиентами. Система, которую мы используем хранит информацию о пользователях в таблице базы данных, которая была создана согласно следующему SQL:
CREATE TABLE `users` (
`id` int(11) NOT NULL auto_increment,
`username` varchar(255) NOT NULL,
`password` varchar(32) NOT NULL,
`first_name` varchar(255) NOT NULL,
`last_name` varchar(255) NOT NULL,
PRIMARY KEY (`id`)
)
Достаточно просто, не так ли? Модель Cake для этой таблицы может быть достаточно ясной:
<?php
class User extends AppModel
{
var $name = 'User';
}
?>
Первое, что нам нужно это отображение и действие логина. Это даст возможность пользователям логиниться и возможность системе обрабатывать информацию, чтобы узнать давать пользователю доступ или нет. Отображение это простая форма HTML, созданная при помощи HTML Хелпера:
/app/views/users/login.thtml
<?if ($error): ?>
<p>The login credentials you supplied could not be recognized. Please try again.</p>
<? endif; ?>
<form action="<?php echo $html->url('/users/login'); ?>" method="post">
<div>
<label for="username">Username:</label>
<?php echo $html->input('User/username', array('size' => 20)); ?>
</div>
<div>
<label for="password">Password:</label>
<?php echo $html->password('User/password', array('size' => 20)); ?>
</div>
<div>
<?php echo $html->submit('Login'); ?>
</div>
</form>
Это отображение предоставляет простую форму логина для пользователей пытающихся получить доступ к системе. Действие для формы это /users/login, находится в Users Controller? и выглядит так:
/app/controllers/users_controller.php (частично)
<?php
class UsersController extends AppController
{
function login()
{
//Не показывать сообщение об ошибке, если данные не были отправлены.
$this->set('error', false);
//Если пользователь отправил данные из формы:
if (!empty($this->data))
{
// Сначала проверим, есть ли пользователи в базе данных
//с именем, которое предоставил пользователь в форме:
$someone = $this->User->findByUsername($this->data['User']['username']);
// На этом этапе $someone это все данные пользователя, или же она пуста.
// Давайте сравним пароль из формы с паролем
//из базы данных.
if(!empty($someone['User']['password']) && $someone['User']['password'] == $this->data['User']['password'])
{
// Заметка: надеемся что пароли в вашей БД хешированы,
// так что ваше сравнение может выглядеть так:
// md5($this->data['User']['password']) == ...
// Это значит, что они были одинаковыми. Теперь мы можем создавать некую основную
//информацию сессии, чтобы запомнить этого пользователя как "залогиненого".
$this->Session->write('User', $someone['User']);
//Теперь, когда у нас они сохранены в сессии, перенаправим их
//на нужную страницу в приложении.
$this->redirect('/clients');
}
//В другом случае, они предоставили не верные данные:
else
{
//Помните переменную $error в отображении? Давайте поставим ее на true:
$this->set('error', true);
}
}
}
function logout()
{
//Перенаправляем пользователя на это действие, если они нажали кнопку Выйти.
//Все что нам здесь нужно, это удалить информацию сессии:
$this->Session->delete('User');
//Ну и наверняка нам нужно перенаправить их куда-нибудь...
$this->redirect('/');
}
}
?>
Не плохо: содержание действия login() может быть меньше 20 линий, если вы были лаконичны. Результат этого действия либо 1: информация пользователя записана в сессию и он перенаправлен на нужную страницу приложения, или 2: отброшен обратно на страницу входа (в дополнении с сообщением об ошибке).
Теперь мы можем аутентифицировать пользователей, давайте сделаем так, что приложение будет отбрасывать пользователей, пытающихся пробраться в систему не из формы логина или «основной» директории клиентов.
Один способ это создать функцию в App Controller?, которая будет делать проверку сессии и отбрасывание.
/app/app_controller.php
<?php
class AppController extends Controller
{
function checkSession()
{
//Если иформация сессии не была установлена...
if (!$this->Session->check('User'))
{
//Отправляет пользователя к экрану логина
$this->redirect('/users/login');
exit();
}
}
}
?>
Теперь у вас есть функция, которую вы можете использовать в любом контроллере, чтобы убедиться что пользователи не пытаются добраться до действий контроллера, не залогинившись до этого. Когда она на месте вы можете проверять доступ на любом уровне – вот некоторые примеры:
<?php
class NotesController extends AppController
{
// Не хотите, чтобы неаутентифицированный пользователь бродил по каким-либо действия
// в этом контроллере? Воспользуйтесь beforeFilter, чтобы запускать checkSession
// перед любым кодом действия.
function beforeFilter()
{
$this->checkSession();
}
}
?>
<?php
class NotesController extends AppController
{
function publicNotes($clientID)
{
//Публичный доступ к этому действию открыт....
}
function edit($noteId)
{
// Но вы хотите, что бы этим действием пользовались только аутентифицированные пользователи.
$this->checkSession();
}
}
?>
Теперь вы получили основы, вы можете усовершенствовать возможности аутентификации или настроить их по своему желанию или нуждам. Интеграция с компонентом ACL Cake может быть отличным шагом.
супер!
жаль что про cake я не слышал пару лет назад...
щас не пришлось бы поддерживать столько беспорядочного кода =)
Полезным будет добавление к даному примеру использование страничной навигации.