В Cake есть контроль доступа через встроенный движок ACL, но как насчет аутентификации пользователей?
Что ж, на данный момент мы установили, что система аутентификации пользователей изменяется от приложения к приложению. Некоторые любят хешированные пароли, другие – LDAP (Облегченный протокол доступа к каталогам), и почти все приложения содержат модели User, которые незначительно отличаются. Теперь мы оставляем это на вас. Изменится ли это? Мы не уверены пока. Сейчас, мы думаем, что большие накладные расходы при встраивании этого в фреймворк того не стоят, потому что создание собственной системы аутентификации пользователей с Cake достаточно просто.
Вам нужно всего три вещи:
В этом примере, мы создадим простую систему аутентификации пользователей для системы управления клиентами. Это вымышленное приложение скорее всего будет использоваться в офисе, чтобы следить за контактной информацией и соответственными заметками клиентов. Вся функциональность системы будет размещена за нашей системой аутентификации пользователей, кроме нескольких отображений, которые будут показывать только имена и титулы клиентов, сохраненные в системе.
Мы начнем с того, что покажем вам как проверить пользователей, которые пытаются получить доступ к системе. Информация об аутентифицированном пользователе будет храниться в сессии PHP, используя компонент сессий. Когда у нас есть информация пользователя в сессии, мы поместим проверки в приложение, чтобы убедится, что пользователь не пытается добраться до мест, куда ему «не нужно» добираться.
На заметку – аутентификация это не то же самое что и контроль доступа. Все что нам нужно в этом примере это являются ли пользователи теми, кем себя заявляют, и дать им основной доступ к частям приложения. Мы будем делать заметки где можно разместить ACL, но пока, давайте сфокусируемся на простой аутентификации пользователей.
Я также должен отметить, что этот пример не претендует на звание какого-то букваря в безопасности приложения. Мы просто хотим дать вам достаточно, чтобы вы могли создать защищенные приложения самостоятельно.
Сначала нам нужен способ хранить информацию о пользователях, пытающихся получить доступ к нашей системе управления клиентами. Система, которую мы используем хранит информацию о пользователях в таблице базы данных, которая была создана согласно следующему SQL:
Table 'users', Fictional Client Management System Database
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 для этой таблицы может быть достаточно ясной:
<?phpclass 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();
}
}
}
?>
Теперь у вас есть функция, которую вы можете использовать в любом контроллере, чтобы убедиться что пользователи не пытаются добраться до действий контроллера, не залогинившись до этого. Когда она на месте вы можете проверять доступ на любом уровне – вот некоторые примеры:
Принудительная аутентификация перед всеми действиями контроллера
<?phpclass NotesController extends AppController{
// Не хотите, чтобы неаутентифицированный пользователь бродил по каким-либо действия // в этом контроллере? Воспользуйтесь beforeFilter, чтобы запускать checkSession
// перед любым кодом действия.
function beforeFilter() {
$this->checkSession(); }
}
?>
Принудительная аутентификация перед одним действием контроллера
<?phpclass NotesController extends AppController{ function
publicNotes($clientID) {
//Публичный доступ к этому действию открыт....
} function
edit($noteId) {
// Но вы хотите, что бы этим действием пользовались только аутентифицированные пользователи.
$this->checkSession(); }
}
?>
Теперь вы получили основы, вы можете усовершенствовать возможности аутентификации или настроить их по своему желанию или нуждам. Интеграция с компонентом ACL Cake может быть отличным шагом.