mirror of
https://github.com/yiisoft/yii.git
synced 2026-03-12 02:56:55 +01:00
615 lines
38 KiB
Plaintext
615 lines
38 KiB
Plaintext
Аутентификация и авторизация
|
||
============================
|
||
|
||
Аутентификация и авторизация необходимы на страницах, доступных лишь некоторым
|
||
пользователям. *Аутентификация* — проверка, является ли некто тем, за кого
|
||
себя выдаёт. Обычно она подразумевает ввод логина и пароля, но также могут быть
|
||
использованы и другие средства, такие как использование смарт-карты, отпечатков
|
||
пальцев и др. *Авторизация* — проверка, может ли аутентифицированный пользователь
|
||
выполнять определённые действия (их часто обозначают как ресурсы). Чаще всего это
|
||
определяется проверкой, назначена ли пользователю определённая роль, имеющая доступ
|
||
к ресурсам.
|
||
|
||
В Yii встроен удобный фреймворк аутентификации и авторизации (auth), который, в
|
||
случае необходимости, может быть настроен под ваши задачи.
|
||
|
||
Центральным компонентом auth-фреймворка является предопределённый
|
||
*компонент приложения «пользователь»* — объект, реализующий интерфейс [IWebUser].
|
||
Данный компонент содержит постоянную информацию о текущем пользователе. Мы можем
|
||
получить к ней доступ из любого места приложения, используя `Yii::app()->user`.
|
||
|
||
Используя этот компонент, мы можем проверить, аутентифицирован ли пользователь, используя
|
||
[CWebUser::isGuest]. Мы можем произвести [вход|CWebUser::login] или [выход|CWebUser::logout].
|
||
Для проверки прав на определённые действия удобно воспользоваться [CWebUser::checkAccess].
|
||
Также есть возможность получить [уникальный идентификатор|CWebUser::name] и другие
|
||
постоянные данные пользователя.
|
||
|
||
Определение класса Identity
|
||
---------------------------
|
||
|
||
Как было упомянуто ранее, аутентификация — это процесс проверки личности пользователя.
|
||
Типичное веб-приложение для такой проверки обычно использует логин и пароль. Тем не менее,
|
||
может потребоваться реализовать проверку другими методами. Чтобы добавить поддержку
|
||
различных методов аутентификации, в Yii имеется соответствующий identity класс.
|
||
|
||
Мы реализуем класс identity, который содержит нужную нам логику аутентификации.
|
||
Такой класс должен реализовать интерфейс [IUserIdentity]. Для различных подходов
|
||
к аутентификации могут быть реализованы различные классы (например, OpenID, LDAP,
|
||
Twitter OAuth или Facebook Connect). При создании своей реализации необходимо
|
||
расширить класс [CUserIdentity], являющийся базовым классом, который реализует
|
||
проверку по логину и паролю.
|
||
|
||
Главная задача при создании класса Identity — реализация метода [IUserIdentity::authenticate].
|
||
Данный метод используется для описания основного алгоритма аутентификации.
|
||
Также данный класс может содержать дополнительную информацию о пользователе, которая
|
||
необходима нам в процессе работы с его сессией.
|
||
|
||
#### Пример
|
||
|
||
В приведённом ниже примере мы используем класс identity и покажем, как реализовать
|
||
аутентификацию по базе данных. Данный подход типичен для большинства приложений.
|
||
Пользователь будет вводить логин и пароль в форму. Введённые данные будем проверять
|
||
с использованием модели [ActiveRecord](/doc/guide/database.ar), соответствующей
|
||
таблице пользователей в БД. В данном примере показано следующее:
|
||
|
||
1. Реализация метода `authenticate()` для проверки данных по БД.
|
||
2. Перекрытие метода `CUserIdentity::getId()` для возврата `_id`. По умолчанию
|
||
в качестве ID возвращается имя пользователя.
|
||
3. Использование метода `setState()` ([CBaseUserIdentity::setState]) для хранения
|
||
информации, необходимой при каждом запросе.
|
||
|
||
~~~
|
||
[php]
|
||
class UserIdentity extends CUserIdentity
|
||
{
|
||
private $_id;
|
||
public function authenticate()
|
||
{
|
||
$record=User::model()->findByAttributes(array('username'=>$this->username));
|
||
if($record===null)
|
||
$this->errorCode=self::ERROR_USERNAME_INVALID;
|
||
else if($record->password!==md5($this->password))
|
||
$this->errorCode=self::ERROR_PASSWORD_INVALID;
|
||
else
|
||
{
|
||
$this->_id=$record->id;
|
||
$this->setState('title', $record->title);
|
||
$this->errorCode=self::ERROR_NONE;
|
||
}
|
||
return !$this->errorCode;
|
||
}
|
||
|
||
public function getId()
|
||
{
|
||
return $this->_id;
|
||
}
|
||
}
|
||
~~~
|
||
|
||
В следующем подразделе мы рассмотрим реализацию входа и выхода, используя наш identity класс
|
||
в методе `login` пользователя. Вся информация, которую мы храним в состояниях
|
||
(путём вызова [CBaseUserIdentity::setState]) будет передана в [CWebUser], который,
|
||
в свою очередь, будет хранить её в постоянном хранилище, таком как сессии.
|
||
К данной информации можно будет обращаться как к свойствам [CWebUser]. В нашем примере
|
||
мы сохранили имя пользователя, используя `$this->setState('title', $record->title);`.
|
||
Как только пользователь успешно войдёт в приложение, мы сможем получить
|
||
его `title` используя `Yii::app()->user->title`.
|
||
|
||
> Info|Инфо: По умолчанию [CWebUser] использует сессии для хранения данных.
|
||
Если вы используете автоматический вход пользователя с помощью cookie
|
||
([CWebUser::allowAutoLogin] выставлен в true), данные пользователя будут
|
||
также сохраняться в cookie. Убедитесь, что эти данные не содержат конфиденциальной
|
||
информации, такой как пароли.
|
||
|
||
Вход и выход
|
||
------------
|
||
|
||
Теперь, когда мы разобрали пример реализации класса identity, мы можем
|
||
использовать его для реализации входа и выхода:
|
||
|
||
~~~
|
||
[php]
|
||
// Аутентифицируем пользователя по имени и паролю
|
||
$identity=new UserIdentity($username,$password);
|
||
if($identity->authenticate())
|
||
Yii::app()->user->login($identity);
|
||
else
|
||
echo $identity->errorMessage;
|
||
…
|
||
// Выходим
|
||
Yii::app()->user->logout();
|
||
~~~
|
||
|
||
Мы создаём новый объект UserIdentity и передаём в его конструктор параметры аутентификации
|
||
(то есть `$username` и `$password`, введённые пользователем). Далее просто вызываем
|
||
метод `authenticate()`. В случае успешной проверки данных мы передаём объект в
|
||
метод [CWebUser::login], который сохраняет информацию в постоянном хранилище
|
||
(по умолчанию в сессиях PHP) и делает её доступной в последующих запросах.
|
||
Если аутентификация не проходит, мы можем получить информацию об ошибке из свойства `errorMessage`.
|
||
|
||
Проверить, является ли пользователь аутентифицированным, очень просто. Для этого можно
|
||
воспользоваться `Yii::app()->user->isGuest`. При использовании постоянного
|
||
хранилища, такого как сессии (по умолчанию) и/или cookie (описано ниже), для хранения
|
||
информации о пользователе, пользователь может оставаться аутентифицированным в
|
||
последующих запросах. В этом случае нет необходимости использовать класс UserIdentity
|
||
и показывать форму входа. [CWebUser] автоматически загрузит необходимую информацию
|
||
из постоянного хранилища и использует её при обращении к `Yii::app()->user->isGuest`.
|
||
|
||
Вход на основе cookie
|
||
---------------------
|
||
|
||
По умолчанию, после некоторого времени бездействия, зависящего от
|
||
[настроек сессии](http://php.net/manual/en/session.configuration.php),
|
||
будет произведён выход из системы. Для того, чтобы этого не происходило,
|
||
необходимо выставить свойства компонента User [allowAutoLogin|CWebUser::allowAutoLogin]
|
||
в true и передать необходимое время жизни cookie в метод [CWebUser::login].
|
||
Пользователь будет автоматически аутентифицирован на сайте в течение указанного
|
||
времени даже в том случае, если он закроет браузер. Данная возможность требует
|
||
поддержки cookie в браузере пользователя.
|
||
|
||
~~~
|
||
[php]
|
||
// Автоматический вход в течение 7 дней.
|
||
// allowAutoLogin для компонента user должен быть выставлен в true.
|
||
Yii::app()->user->login($identity,3600*24*7);
|
||
~~~
|
||
|
||
Как уже упоминалось выше, когда включен вход на основе cookie, состояния,
|
||
сохраняемые при помощи [CBaseUserIdentity::setState], также будут сохраняться в cookie.
|
||
При следующем входе состояния считываются из cookie и становятся доступными через `Yii::app()->user`.
|
||
|
||
Несмотря на то, что в Yii имеются средства для предотвращения подмены состояний в cookie
|
||
на стороне клиента, не рекомендуется хранить в состояниях важную информацию.
|
||
Гораздо более правильным решением будет хранение её в постоянном хранилище на стороне
|
||
сервера (например, в БД).
|
||
|
||
Кроме того, для серьёзных приложений рекомендуется улучшить стратегию входа по cookie
|
||
следующим образом:
|
||
|
||
* При успешном входе после заполнения формы генерируем и храним случайный ключ
|
||
как в cookie состояния, так и в постоянном хранилище на сервере (т.е. в БД).
|
||
|
||
* При последующих запросах, когда аутентификация производится на основе
|
||
информации в cookie, мы сравниваем две копии ключа и, перед тем, как
|
||
аутентифицировать пользователя, проверяем, что они равны.
|
||
|
||
* Если пользователь входит через форму ещё раз, ключ регенерируется.
|
||
|
||
Данная стратегия исключает возможность повторного использования старого
|
||
состояния cookie, в котором может находится устаревшая информация.
|
||
|
||
Для реализации нужно переопределить два метода:
|
||
|
||
* [CUserIdentity::authenticate()]. Здесь производится аутентификация.
|
||
Если пользователь аутентифицирован, необходимо сгенерировать новый ключ и сохранить его
|
||
в cookie состояния (при помощи [CBaseUserIdentity::setState]) и в постояное хранилище
|
||
на стороне сервера (например, в БД).
|
||
|
||
* [CWebUser::beforeLogin()]. Вызывается перед входом. Необходимо проверить
|
||
соответствие ключей в состоянии и базе данных.
|
||
|
||
Фильтр контроля доступа
|
||
-----------------------
|
||
|
||
Фильтр контроля доступа — схема авторизации, подразумевающая предварительную проверку
|
||
прав текущего пользователя на вызываемое действие контроллера. Авторизация
|
||
производится по имени пользователя, IP-адресу и типу запроса. Данный фильтр называется
|
||
«[accessControl|CController::filterAccessControl]».
|
||
|
||
> Tip|Подсказка: Фильтр контроля доступа достаточен для реализации простых систем.
|
||
Для более сложных вы можете использовать доступ на основе ролей
|
||
(RBAC), который будет описан ниже.
|
||
|
||
Для управления доступом к действиям контроллера необходимо переопределить метод
|
||
[CController::filters] (более подробно описано в разделе
|
||
[Фильтры](/doc/guide/basics.controller#filter)).
|
||
|
||
~~~
|
||
[php]
|
||
class PostController extends CController
|
||
{
|
||
…
|
||
public function filters()
|
||
{
|
||
return array(
|
||
'accessControl',
|
||
);
|
||
}
|
||
}
|
||
~~~
|
||
|
||
Выше было описано, что фильтр [access
|
||
control|CController::filterAccessControl] применяется ко всем действиям
|
||
контроллера `PostController`. Правила доступа, используемые фильтром, определяются
|
||
переопределением метода [CController::accessRules] контроллера.
|
||
|
||
~~~
|
||
[php]
|
||
class PostController extends CController
|
||
{
|
||
…
|
||
public function accessRules()
|
||
{
|
||
return array(
|
||
array('deny',
|
||
'actions'=>array('create', 'edit'),
|
||
'users'=>array('?'),
|
||
),
|
||
array('allow',
|
||
'actions'=>array('delete'),
|
||
'roles'=>array('admin'),
|
||
),
|
||
array('deny',
|
||
'actions'=>array('delete'),
|
||
'users'=>array('*'),
|
||
),
|
||
);
|
||
}
|
||
}
|
||
~~~
|
||
|
||
Приведённый код описывает три правила, каждое из которых представлено в виде массива.
|
||
Первый элемент массива может принимать значения `'allow'` или `'deny'`. Остальные
|
||
пары ключ-значение задают параметры правила. Правила, заданные выше, можно
|
||
прочитать следующим образом: действия `create` и `edit` не могут быть выполнены
|
||
анонимными пользователями, а действие `delete` может быть выполнено только
|
||
пользователями с ролью `admin`.
|
||
|
||
Правила доступа разбираются поочерёдно в порядке их описания. Первое правило,
|
||
совпадающее с текущими данными (например, с именем пользователя, ролью или
|
||
IP) определяет результат авторизации. Если это разрешающее правило, действие
|
||
может быть выполнено, если запрещающее — не может. Если ни одно из правил не
|
||
совпало — действие может быть выполнено.
|
||
|
||
> Tip|Подсказка: Чтобы быть уверенным, что действие не будет выполнено,
|
||
> необходимо запретить все действия, которые не разрешены, определив соответствующее
|
||
> правило в конце списка:
|
||
> ~~~
|
||
> [php]
|
||
> return array(
|
||
> // … разные правила …
|
||
> // это правило полностью запрещает действие 'delete'
|
||
> array('deny',
|
||
> 'actions'=>array('delete'),
|
||
> ),
|
||
> );
|
||
> ~~~
|
||
> Данное правило необходимо, так как если ни одно из правил не совпадёт,
|
||
> действие продолжит выполнение.
|
||
|
||
Правило доступа может включать параметры, по которым проверяется совпадение:
|
||
|
||
- [actions|CAccessRule::actions]: позволяет указать действия в виде массива
|
||
их идентификаторов. Сравнение регистронезависимо;
|
||
|
||
- [controllers|CAccessRule::controllers]: позволяет указать контроллеры в виде
|
||
массива их идентификаторов. Сравнение регистронезависимо.
|
||
|
||
- [users|CAccessRule::users]: позволяет указать пользователей. Для сравнения
|
||
используется [CWebUser::name]. Сравнение регистронезависимо. В параметре могут быть
|
||
использованы следующие специальные символы:
|
||
|
||
- `*`: любой пользователь, включая анонимного.
|
||
- `?`: анонимный пользователь.
|
||
- `@`: аутентифицированный пользователь.
|
||
|
||
- [roles|CAccessRule::roles]: позволяет указать роли, используя
|
||
[доступ на основе ролей](/doc/guide/topics.auth#sec5), описанный в следующем
|
||
разделе. В частном случае, правило применится, если [CWebUser::checkAccess]
|
||
вернёт true для одной из ролей. Роли стоит использовать в разрешающих
|
||
правилах так как роль ассоциируется с возможностью выполнения какого-либо действия.
|
||
Также стоит отметить, что, несмотря на то, что мы используем термин «роль»,
|
||
значением может быть любой элемент auth-фреймворка, такой как роли,
|
||
задачи или операции;
|
||
|
||
- [ips|CAccessRule::ips]: позволяет указать IP-адрес;
|
||
|
||
- [verbs|CAccessRule::verbs]: позволяет указать тип запросов (например,
|
||
`GET` или `POST`). Сравнение регистронезависимо;
|
||
|
||
- [expression|CAccessRule::expression]: позволяет указать выражение PHP, вычисление
|
||
которого будет определять совпадение правила. Внутри выражения доступна переменная
|
||
`$user`, указывающая на `Yii::app()->user`.
|
||
|
||
|
||
Обработка запроса авторизации
|
||
-----------------------------
|
||
|
||
При неудачной авторизации, т.е. когда пользователю запрещено выполнять указанное
|
||
действие, происходит следующее:
|
||
|
||
- Если пользователь не аутентифицирован и в свойстве [loginUrl|CWebUser::loginUrl]
|
||
компонента user задан URL страницы входа, браузер будет перенаправлен на эту страницу.
|
||
Заметим, что по умолчанию [loginUrl|CWebUser::loginUrl] перенаправляет к странице `site/login`;
|
||
|
||
- Иначе будет отображена ошибка HTTP с кодом 403.
|
||
|
||
При задании свойства [loginUrl|CWebUser::loginUrl] используется как относительный,
|
||
так и абсолютный URL. Также можно передать массив, который будет использоваться
|
||
[CWebApplication::createUrl] при формировании URL. Первый элемент массива
|
||
задаёт [маршрут](/doc/guide/basics.controller#route) до действия login вашего
|
||
контроллера, а остальные пары имя-значение — GET-параметры. К примеру,
|
||
|
||
~~~
|
||
[php]
|
||
array(
|
||
…
|
||
'components'=>array(
|
||
'user'=>array(
|
||
// это значение устанавливается по умолчанию
|
||
'loginUrl'=>array('site/login'),
|
||
),
|
||
),
|
||
)
|
||
~~~
|
||
|
||
Если браузер был перенаправлен на страницу входа и вход удачный, вам может понадобиться
|
||
перенаправить пользователя к той странице, на которой неудачно прошла авторизация.
|
||
Как же узнать URL той страницы? Мы можем получить эту информацию из свойства
|
||
[returnUrl|CWebUser::returnUrl] компонента user. Имея её, мы можем сделать
|
||
перенаправление:
|
||
|
||
~~~
|
||
[php]
|
||
Yii::app()->request->redirect(Yii::app()->user->returnUrl);
|
||
~~~
|
||
|
||
Контроль доступа на основе ролей
|
||
--------------------------------
|
||
|
||
Контроль доступа на основе ролей (RBAC) — простой, но мощный способ централизованного
|
||
контроля доступа. Для сравнения данного метода с другими обратитесь к
|
||
[статье в Википедии](http://ru.wikipedia.org/wiki/%D3%EF%F0%E0%E2%EB%E5%ED%E8%E5_%E4%EE%F1%F2%F3%EF%EE%EC_%ED%E0_%EE%F1%ED%EE%E2%E5_%F0%EE%EB%E5%E9).
|
||
|
||
В Yii иерархический RBAC реализован через компонент [authManager|CWebApplication::authManager].
|
||
Ниже мы сначала опишем основы данной схемы, затем то, как описывать данные,
|
||
необходимые для авторизации. В завершение мы покажем, как использовать эти данные для
|
||
контроля доступа.
|
||
|
||
### Общие принципы
|
||
|
||
Основным понятием в RBAC Yii является *элемент авторизации*. Элемент авторизации —
|
||
это права на выполнение какого-либо действия (создать новую запись в
|
||
блоге, управление пользователями). В зависимости от структуры и цели,
|
||
элементы авторизации могут быть разделены на *операции*,
|
||
*задачи* и *роли*. Роль состоит из задач. Задача состоит из операций.
|
||
Операция — разрешение на какое-либо действие (дальше не делится).
|
||
К примеру, в системе может быть роль `администратор`, состоящая из задач
|
||
`управление записями` и `управление пользователями`. Задача `управление пользователями`
|
||
может состоять из операций `создать пользователя`, `редактировать пользователя` и
|
||
`удалить пользователя`. Для достижения большей гибкости, роль в Yii может состоять
|
||
из других ролей и операций. Задача может состоять из других задач. Операция — из
|
||
других операций.
|
||
|
||
Элемент авторизации однозначно идентифицируется его уникальным именем.
|
||
|
||
Элемент авторизации может быть ассоциирован с *бизнес-правилом* — PHP-кодом,
|
||
который будет использоваться при проверке доступа. Пользователь получит доступ
|
||
к элементу только если код вернёт true. К примеру, при определении операции `updatePost`,
|
||
будет не лишним добавить бизнес-правило, проверяющее соответствие ID пользователя
|
||
ID автора записи. То есть, доступ к редактированию записи имеет только её автор.
|
||
|
||
Используя элементы авторизации мы можем построить *иерархию авторизации*.
|
||
Элемент `A` является родителем элемента `B` в иерархии, если
|
||
`A` состоит из `B` (или `A` наследует права, представленные в `B`).
|
||
Элемент может иметь несколько потомков и несколько предков.
|
||
Поэтому иерархия авторизации является скорее частично упорядоченным графом, чем
|
||
деревом. В ней роли находятся на верхних уровнях, операции — на нижних. Посередине
|
||
расположены задачи.
|
||
|
||
После построения иерархии авторизации мы можем назначать роли из неё пользователям
|
||
нашего приложения. Пользователь получает все права роли, которая ему назначена.
|
||
К примеру, если назначить пользователю роль `администратор`, он получит административные
|
||
полномочия, такие как `управление записями` или `управление пользователями`
|
||
(и соответствующие им операции, такие как `создать пользователя`).
|
||
|
||
А теперь самое приятное. В действии контроллера мы хотим проверить, может
|
||
ли текущий пользователь удалить определённую запись. При использовании иерархии RBAC и
|
||
назначенной пользователю роли, это делается очень просто:
|
||
|
||
~~~
|
||
[php]
|
||
if(Yii::app()->user->checkAccess('deletePost'))
|
||
{
|
||
// удаляем запись
|
||
}
|
||
~~~
|
||
|
||
Настройка менеджера авторизации
|
||
-------------------------------
|
||
|
||
Перед тем, как мы перейдём к построению иерархии авторизации и непосредственно
|
||
проверке доступа, нам потребуется настроить компонент приложения
|
||
[authManager|CWebApplication::authManager]. В Yii есть два типа менеджеров
|
||
авторизации: [CPhpAuthManager] и [CDbAuthManager]. Первый использует для
|
||
хранения данных PHP, второй — базу данных. При настройке
|
||
[authManager|CWebApplication::authManager] необходимо указать, который из
|
||
компонентов мы собираемся использовать и указать начальные значения свойств
|
||
компонента. К примеру,
|
||
|
||
~~~
|
||
[php]
|
||
return array(
|
||
'components'=>array(
|
||
'db'=>array(
|
||
'class'=>'CDbConnection',
|
||
'connectionString'=>'sqlite:path/to/file.db',
|
||
),
|
||
'authManager'=>array(
|
||
'class'=>'CDbAuthManager',
|
||
'connectionID'=>'db',
|
||
),
|
||
),
|
||
);
|
||
~~~
|
||
|
||
После этого мы можем обращаться к компоненту [authManager|CWebApplication::authManager]
|
||
используя `Yii::app()->authManager`.
|
||
|
||
Построение иерархии авторизации
|
||
-------------------------------
|
||
|
||
Построение иерархии авторизации состоит из трёх этапов: задания элементов
|
||
авторизации, описания связей между ними и назначение ролей пользователям.
|
||
Компонент [authManager|CWebApplication::authManager] предоставляет полный набор
|
||
API для выполнения поставленных задач.
|
||
|
||
Для определения элемента авторизации следует воспользоваться одним из приведённых
|
||
ниже методов:
|
||
|
||
- [CAuthManager::createRole]
|
||
- [CAuthManager::createTask]
|
||
- [CAuthManager::createOperation]
|
||
|
||
После того, как мы определили набор элементов авторизации, мы можем воспользоваться
|
||
следующими методами для установки связей:
|
||
|
||
- [CAuthManager::addItemChild]
|
||
- [CAuthManager::removeItemChild]
|
||
- [CAuthItem::addChild]
|
||
- [CAuthItem::removeChild]
|
||
|
||
После этого мы назначаем роли пользователям:
|
||
|
||
- [CAuthManager::assign]
|
||
- [CAuthManager::revoke]
|
||
|
||
Приведём пример построения иерархии авторизации с использованием данного API:
|
||
|
||
~~~
|
||
[php]
|
||
$auth=Yii::app()->authManager;
|
||
|
||
$auth->createOperation('createPost','создание записи');
|
||
$auth->createOperation('readPost','просмотр записи');
|
||
$auth->createOperation('updatePost','редактирование записи');
|
||
$auth->createOperation('deletePost','удаление записи');
|
||
|
||
$bizRule='return Yii::app()->user->id==$params["post"]->authID;';
|
||
$task=$auth->createTask('updateOwnPost','редактирование своей записи',$bizRule);
|
||
$task->addChild('updatePost');
|
||
|
||
$role=$auth->createRole('reader');
|
||
$role->addChild('readPost');
|
||
|
||
$role=$auth->createRole('author');
|
||
$role->addChild('reader');
|
||
$role->addChild('createPost');
|
||
$role->addChild('updateOwnPost');
|
||
|
||
$role=$auth->createRole('editor');
|
||
$role->addChild('reader');
|
||
$role->addChild('updatePost');
|
||
|
||
$role=$auth->createRole('admin');
|
||
$role->addChild('editor');
|
||
$role->addChild('author');
|
||
$role->addChild('deletePost');
|
||
|
||
$auth->assign('reader','readerA');
|
||
$auth->assign('author','authorB');
|
||
$auth->assign('editor','editorC');
|
||
$auth->assign('admin','adminD');
|
||
~~~
|
||
|
||
После создания элементов авторизации, компонент [authManager|CWebApplication::authManager]
|
||
(или его наследники, например, [CPhpAuthManager], [CDbAuthManager]) загружает их автоматически.
|
||
То есть, приведённый код запускается один раз, а НЕ для каждого запроса.
|
||
|
||
> Info|Инфо: Довольно громоздкий пример выше предназначен скорее для демонстрации.
|
||
Разработчикам обычно требуется создать интерфейс администратора и дать возможность
|
||
пользователям самим построить иерархию авторизации.
|
||
|
||
|
||
Использование бизнес-правил
|
||
---------------------------
|
||
|
||
При построении иерархии авторизации мы можем назначить роль, задачу или операцию
|
||
*бизнес-правилу*. Также мы можем указать его при назначении роли пользователю.
|
||
Бизнес-правило — PHP-код, использующийся при проверке доступа. Возвращаемое данным кодом
|
||
значение определяет, применять ли данную роль к текущему пользователю.
|
||
В примере выше мы применили бизнес-правило для описания задачи `updateOwnPost`.
|
||
В нём мы проверяем, совпадает ли ID текущего пользователя с ID автора записи.
|
||
Информация о записи в массиве `$params` передаётся разработчиком при проверке
|
||
доступа.
|
||
|
||
|
||
### Проверка доступа
|
||
|
||
Для проверки доступа нам необходимо знать имя элемента авторизации.
|
||
К примеру, чтобы проверить, может ли текущий пользователь создать запись,
|
||
необходимо узнать, имеет ли он права, описанные операцией `createPost`.
|
||
После этого мы можем вызвать [CWebUser::checkAccess]:
|
||
|
||
~~~
|
||
[php]
|
||
if(Yii::app()->user->checkAccess('createPost'))
|
||
{
|
||
// создаём запись
|
||
}
|
||
~~~
|
||
|
||
Если правило авторизации использует бизнес-правило, требующее дополнительных
|
||
параметров, необходимо их передать. К примеру, чтобы проверить, может ли
|
||
пользователь редактировать запись, мы передаём данные о записи в `$params`:
|
||
|
||
~~~
|
||
[php]
|
||
$params=array('post'=>$post);
|
||
if(Yii::app()->user->checkAccess('updateOwnPost',$params))
|
||
{
|
||
// обновляем запись
|
||
}
|
||
~~~
|
||
|
||
|
||
### Использование ролей по умолчанию
|
||
|
||
Некоторым веб-приложениям требуются очень специфичные роли, которые назначаются
|
||
каждому или почти каждому пользователю. К примеру, нам необходимо наделить некоторыми
|
||
правами всех аутентифицированных пользователей. Определять явно и хранить роли для
|
||
каждого пользователя в этом случае явно неудобно. Для решения этой проблемы можно
|
||
использовать *роли по умолчанию*.
|
||
|
||
Роль по умолчанию автоматически назначается каждому пользователю.
|
||
При вызове [CWebUser::checkAccess] сначала проверяются роли по умолчанию. Назначать
|
||
их явно не требуется.
|
||
|
||
Роли по умолчанию описываются в свойстве [CAuthManager::defaultRoles].
|
||
К примеру, приведённая ниже конфигурация описывает две роли по умолчанию:
|
||
`authenticated` и `admin`.
|
||
|
||
~~~
|
||
[php]
|
||
return array(
|
||
'components'=>array(
|
||
'authManager'=>array(
|
||
'class'=>'CDbAuthManager',
|
||
'defaultRoles'=>array('authenticated', 'admin'),
|
||
),
|
||
),
|
||
);
|
||
~~~
|
||
|
||
Так как роль по умолчанию назначается каждому пользователю, обычно требуется
|
||
использовать бизнес-правило, определяющее, к каким именно пользователям её применять.
|
||
К примеру, следующий код определяет две роли: `authenticated` и `admin`,
|
||
которые соответственно применяются к аутентифицированным пользователям и пользователям
|
||
с именем `admin`.
|
||
|
||
~~~
|
||
[php]
|
||
$bizRule='return Yii::app()->user->name === "admin";';
|
||
$auth->createRole('admin', 'администратор', $bizRule);
|
||
|
||
$bizRule='return Yii::app()->user->isGuest;';
|
||
$auth->createRole('guest', 'гость', $bizRule);
|
||
~~~
|
||
|
||
> Info|Информация: Начиная с версии 1.1.11 массив `$params`, передаваемый в
|
||
> бизнес-правило, всегда содежит ключ `userId` с id пользвателя, для которого проверяется
|
||
> правило. Это особенно удобно при использовании [CDbAuthManager::checkAccess()]
|
||
> или [CPhpAuthManager::checkAccess()] когда `Yii::app()->user` не
|
||
> является пользователем, которого вы проверяете.
|
||
|
||
<div class="revision">$Id$</div> |