Аутентификация с использованием Jelly и Jelly-Auth -- часть 2

Просмотров: 5753Комментарии: 6
Web frameworks

Briefly in English
Next part of tutorial on using Kohana 3 Jelly and Jelly-Auth (autologin, built-in role system application). Will be translated soon.


Часть 1


В этой части добавятся автологин и использование встроенной ролевой системы. Однако сначала проведу работу над ошибками

1. вместо
[code lang="php"]

$this->auth = Jelly_Auth::instance();

[/code]
лучше
[code lang="php"]

$this->auth = Auth::instance();

[/code]
Thanks SpadXIII


2. модуль ORM здесь действительно не нужен и его можно спокойно отключить (спасибо Sezarin).



3. Для удобства можно ввести свойство Controller_admin::$user и определять его в before():
[code lang="php"]

$this->user = $this->auth->get_user();

[/code]


3. В описании поля email модели стоит только проверка на уникальность, но нет проверки на пустое поле. Поэтому если кто-то не указал электронную почту, а потом это же делает другой, то выбрасывается Database Exception на неуникальность полей под индексом UNIQUE (которое не ловится, поскольку стоит catch на Validation_Exception). Я не нашел лучшего способа исправить ситуацию, кроме как наследовать User, переопределив метод initialize() таким образом (если нет желания переписать в нем все поля полностью):

[code lang="php"]

public static function initialize(Jelly_Meta $meta)

{

$meta->fields = array(

'email' => new Field_Email(array(

'unique' => TRUE,

'rules' => array(

'not_empty' => array(TRUE),

)

)),

);

parent::initialize($meta);

}

[/code]


Кроме того, был малость исправлен и дополнен вывод сообщений об ошибках при валидации.


Сделаем автологин.
Для этого нужно
а) изменить форму, добавив чекбокс


б) добавить на страницу логина обработку чекбокса, переписав проверку $_POST таким образом

[code lang="php"]

// try to login

if ($_POST)

{

$username = $_POST['username'];

$password = $_POST['password'];

$remember = isset($_POST['remember']) ? TRUE : FALSE;

if ($this->auth->login($username, $password, $remember))

{

Request::instance()->redirect('admin/index');

} else {

$errors = array('Login or password incorrect');

}

}

[/code]


в) переписать защищенные методы с учетом включенного автологина. В моем случае пришлось проверять право на просмотр страницы с помощью $this->auth->logged_in('login'), что автоматически пытается заавтологинить юзера.


Для реализации простейшей ролевой системы вполне пригоден имеющийся в модуле Jelly-Auth функционал -- метод has_role($role). Например, разрешим добавлять пользователя только администратору. Однако для этого нужно предоставить возможность назначать роли пользователям.


Надо
а) в методе контроллера action_users() в ветке 'edit' добавить переменные, содержащие коллекцию ролей системы и массив активных ролей пользователя:

[code lang="php"]

$roles = Jelly::select('roles')

->execute();

...

if ($is_saved)

{

$this->template->content = 'User profile was updated';

} else {

// output user profile form

$this->template->content = $content

->set('id', $user->id)

->set('username', $user->username)

->set('email', $user->email)

->set('user_roles', $user->roles->as_array())

->set('roles', $roles);

}

[/code]


б) соответственно, в форме ('views/admin/edit_user') нужно вставить массив чекбоксов типа

[code lang="php"]

Assigned roles

    <?php

    $role_ids = array();

    foreach ($user_roles as $ur)

    {

    $role_ids[] = $ur['id'];

    }

    foreach ($roles as $role)

    {

    ?>

  • <?php echo Form::checkbox('roles[]', $role['id'], in_array($role['id'], $role_ids), array('id' => 'roles_'.$role['id'])).' '

    .Form::label('roles_'.$role['id'], $role['name'].'
    '.$role['description']);

    ?>

  • <?

    }

    ?>

[/code]

Первый foreach выглядит не очень красиво, но я в силу неопытности не нашел лучшего способа извлечь массив role IDs из ассоциативного массива.


в) Остается обработать приходящий в POST массив номеров ролей:

[code lang="php"]

$user->roles = isset($_POST['roles']) ? $_POST['roles'] : array();

[/code]


Далее можем, например, разрешить добавление нового пользователя только админу

[code lang="php"]

if ($this->user->has_role('admin'))

...

[/code]


Увы, хранение данных пользователя в сессии приводит к тому, что внесенные изменения вступают в силу после перелогина.

Разумеется, такая простая ролевая система может помочь только в несложных случаях. Поэтому буду думать над продолжением.


Скачать / Download 80 (zipped ~11 KiB)

Комментариев: 6 RSS

1 Sezarin 23-04-2010 19:46

Неплохой пример реализации сложных вещей просто...

Я думаю, у Jelly - большое будущее.

Кстати, со вчера на Github (http://github.com/jonathangeiger/kohana-jelly) появилась версия с документацией на русском.

Спасибо Сергею Гладковскому! (http://github.com/smgladkovskiy)

2 Александр Купреев 23-04-2010 22:05

да, Jelly мне кажется достаточно удобным инструментом, хотя тут не имею большого опыта. А на русском языке вообще приятно читать smile

3 biakaveron 11-05-2010 14:32

1.

if ($_POST)
{
    $username = $_POST['username'];
    $password = $_POST['password'];
...

Добавьте проверку на наличие этих ключей. Arr::get() я уже на автопилоте подставляю в любом месте, где работаю с массивами smile

2. А зачем пункт "в" в реализации автологина? Для этого обычно используется метод Auth::instance()->auto_login(), который пробует залогиниться на основании кук (вернет TRUE, если получилось). Пихаем его в before(), если не прокатило, то уже тогда предлагаем залогиниться.

4 Александр Купреев 11-05-2010 20:33

пункт в) нужен из-за того, что я изначально отказался от менеджмента доступа к страницам в before(), решив разбираться в каждом методе отдельно smile а так конечно -- вы абсолютно правы

5 Anree 13-05-2010 16:11

Александр спасибо Вам за столь интересные статьи.

Первый foreach выглядит не очень красиво, но я в силу неопытности не нашел лучшего способа извлечь массив role IDs из ассоциативного массива.

Я немного поправил код в вашем примере. Надеюсь в лучшую сторону )

1. Контроллер action_users(), ветка 'edit'

...
if ($is_saved)
{
    $this->template->content = 'User profile was updated';
} else {
    // output user profile form
    $this->template->content = $content
        ->set('id', $user->id)
        ->set('username', $user->username)
        ->set('email', $user->email)
        ->set('user_roles', $user->roles->as_array('id'))
        // т.е. выводим ассоциативный массив ролей, где ключем
        // является поле ID
        ->set('roles', $roles); 
}
...

2.Форма views/admin/edit_user

Assigned roles
<?php 
foreach ($roles as $role)
{
?>
<?php echo Form::checkbox('roles[]', $role['id'], array_key_exists($role['id'], $user_roles),
array('id' => 'roles_'.$role['id'])) . ' ' . Form::label('roles_'.$role['id'], $role['name'].''.$role['description']);
?>
<? 
}
?>

Т.е. я в форме убрал лишний цикл и изменил поиск ID в массиве ролей пользователей.

6 Александр Купреев 17-05-2010 15:02

Anree, спасибо за отзыв и простите, что поздно отвечаю -- провайдер подорвал доверие :(

Спасибо за правки, самое то!

Оставьте комментарий!


Используйте нормальные имена.

     

  

Если вы уже зарегистрированы как комментатор или хотите зарегистрироваться, укажите пароль и свой действующий email. При регистрации на указанный адрес придет письмо с кодом активации и ссылкой на ваш персональный аккаунт, где вы сможете изменить свои данные, включая адрес сайта, ник, описание, контакты и т.д., а также подписку на новые комментарии.

MaxSiteAuth. Войти через loginza

(обязательно)