Yii 1. Авторизация - пользователи и роли в базе данных
Введение
Процесс настройки аутентификации и авторизации расписан в нескольких официальных и полуофициальных источниках:http://www.yiiframework.com/doc/guide/1.1/ru/topics.auth
http://yiiframework.ru/doc/guide/ru/topics.auth
http://yiiframework.ru/doc/cookbook/ru/access.rbac.file
Но ни в одном из этих источников нет исчерпывающих рекомендаций для построения авторизации для случая, когда пользователи, роли и прочие правила хранятся в базе данных. Хотя схема для базы данных MySQL входит в поставку Yii:
framework/web/auth/schema-mysql.sql
Эта схема содержит описание трёх таблиц: AuthAssignment, AuthItem и AuthItemChild. Схема:
До этого я завёл таблицы для пользоватлей и ролей: user и user_role:
Базовая настройка прав доступа
Модель User у меня такая:
<?php
/**
* This is the model class for table "user".
*
* The followings are the available columns in table 'user':
* @property integer $id
* @property string $username
* @property string $password
* @property string $email
* @property integer $user_role_id
*
* The followings are the available model relations:
* @property UserRole $userRole
*/
class User extends CActiveRecord {
public function tableName() {
return 'user';
}
public function rules() {
return array(
array('username, password, email', 'required'),
array('user_role_id', 'numerical', 'integerOnly'=>true),
array('username, email', 'length', 'max'=>128),
array('password', 'length', 'max'=>64),
array('id, username, password, email, user_role_id', 'safe', 'on'=>'search'),
);
}
public function relations() {
return array(
'userRole' => array(self::BELONGS_TO, 'UserRole', 'user_role_id'),
);
}
public function attributeLabels() {
return array(
'id' => 'ID',
'username' => Yii::t("main", "Username"),
'password' => Yii::t("main", "Password"),
'email' => Yii::t("main", "Email"),
'user_role_id' => Yii::t("main", "Role")
);
}
public function search() {
$criteria=new CDbCriteria;
$criteria->compare('id',$this->id);
$criteria->compare('username',$this->username,true);
$criteria->compare('email',$this->email,true);
$criteria->compare('user_role_id',$this->role,true);
return new CActiveDataProvider($this, array(
'criteria'=>$criteria,
));
}
public static function model($className=__CLASS__) {
return parent::model($className);
}
public function validatePassword($password) {
return CPasswordHelper::verifyPassword($password,$this->password);
}
public function hashPassword($password) {
return CPasswordHelper::hashPassword($password);
}
protected function beforeSave() {
$this->password = hashPassword($this->password);
return parent::beforeSave();
}
}
Переопределённый класс CUserIdentity у меня такой (/protected/components/Useridentity):
<?php
/**
* UserIdentity represents the data needed to identity a user.
* It contains the authentication method that checks if the provided
* data can identity the user.
*/
class UserIdentity extends CUserIdentity
{
private $_id;
public function authenticate()
{
$username=strtolower($this->username);
$user=User::model()->find('LOWER(username)=?',array($username));
if($user===null)
$this->errorCode=self::ERROR_USERNAME_INVALID;
else if(!$user->validatePassword($this->password))
$this->errorCode=self::ERROR_PASSWORD_INVALID;
else
{
$this->_id=$user->id;
$this->username=$user->username;
$this->setState('role', $user->userRole->name);
$this->errorCode=self::ERROR_NONE;
}
return $this->errorCode==self::ERROR_NONE;
}
public function getId()
{
return $this->_id;
}
}
Переопределённый класс CWebUser у меня выглядит так (/protected/components/WebUser.php):
<?php
class WebUser extends CWebUser {
private $_model = null;
function getRole() {
if($user = $this->getModel()){
return $user->userRole->name;
}
}
private function getModel(){
if (!$this->isGuest && $this->_model === null){
$this->_model = User::model()->findByPk($this->id);
}
return $this->_model;
}
}
В конфиге прописываем авторизацию через базу данных (перед этим, само собой, определены настройки подключения к базе данных). /protected/config/main.php:
'authManager'=>array(
'class'=>'CDbAuthManager',
'connectionID'=>'db',
'defaultRoles' => array('guest')
),
Чтобы заполнить таблицы правил и ролей пользователей, создадим скрипт /protected/commands/AccessCommand.php и заполним его своими настройками. Я добавил в правила все интересующие меня действия из моих контроллеров. У меня получилось так:
class AccessCommand extends CConsoleCommand {
public function actionAddRules() {
$auth=Yii::app()->authManager;
$auth->createOperation('login',Yii::t("main", "Login"));
$auth->createOperation('indexAuthor',Yii::t("main", "View list of authors"));
$auth->createOperation('createAuthor',Yii::t("main", "Create author"));
$auth->createOperation('adminAuthor',Yii::t("main", "Administrate authors"));
$auth->createOperation('updateAuthor',Yii::t("main", "Update author"));
$auth->createOperation('deleteAuthor',Yii::t("main", "Delete author"));
$auth->createOperation('makePageAuthor',Yii::t("main", "Make site's page for that author"));
$auth->createOperation('indexBook',Yii::t("main", "View list of books"));
$auth->createOperation('createBook',Yii::t("main", "Create book"));
$auth->createOperation('adminBook',Yii::t("main", "Administrate books"));
$auth->createOperation('updateBook',Yii::t("main", "Update book"));
$auth->createOperation('deleteBook',Yii::t("main", "Delete book"));
$auth->createOperation('selectImageBook',Yii::t("main", "Make list of book's images"));
$auth->createOperation('getAuthorsBook',Yii::t("main", "Get authors of book"));
$auth->createOperation('indexAuthorBook',Yii::t("main", "View list of links authors and books"));
$auth->createOperation('createAuthorBook',Yii::t("main", "Create link author and book"));
$auth->createOperation('adminAuthorBook',Yii::t("main", "Administrate link author and books"));
$auth->createOperation('updateAuthorBook',Yii::t("main", "Update link author and book"));
$auth->createOperation('deleteAuthorBook',Yii::t("main", "Delete link author and book"));
$role=$auth->createRole('guest');
$role->addChild('login');
$role=$auth->createRole('user');
$role->addChild('guest');
$role=$auth->createRole('manager');
$role->addChild('user');
$role->addChild('indexAuthor');
$role->addChild('createAuthor');
$role->addChild('adminAuthor');
$role->addChild('updateAuthor');
$role->addChild('deleteAuthor');
$role->addChild('makePageAuthor');
$role->addChild('indexBook');
$role->addChild('createBook');
$role->addChild('adminBook');
$role->addChild('updateBook');
$role->addChild('deleteBook');
$role->addChild('selectImageBook');
$role->addChild('getAuthorsBook');
$role->addChild('indexAuthorBook');
$role->addChild('createAuthorBook');
$role->addChild('adminAuthorBook');
$role->addChild('updateAuthorBook');
$role->addChild('deleteAuthorBook');
$role=$auth->createRole('administrator');
$role->addChild('manager');
}
public function actionAssignUsers() {
Yii::app()->authManager->assign('administrator', '2');
Yii::app()->authManager->assign('manager', '3');
Yii::app()->authManager->assign('manager', '4');
}
}
Как видно из кода, пользователи с ролями guest и user могут только логиниться, пользователи manager и administrator обладают разными другими правами, которые можно будет в контроллерах обрабатывать примерно так:
public function actionIndex() {
if (Yii::app()->user->checkAccess('indexAuthor')) {
$dataProvider=new CActiveDataProvider('Author');
$this->render('index', array('dataProvider' => $dataProvider));
} else { // Если прав нет, то перенаправляем на авторизацию
$this->redirect(array('site/login'));
}
}
Но для моей задачи достаточно общей проверки (роли пользователя, а не каждого отдельного действия) в таком виде (прописывается в контроллерах):
public function filters() {
return array('accessControl');
}
public function accessRules() {
return array(
array('allow',
'actions'=>array('index', 'view', 'create', 'update', 'makePage'),
'roles' => array('manager')
),
array('allow',
'actions' => array('admin', 'delete'),
'roles' => array('administrator')
),
array('deny',
'users' => array('*'),
),
);
}
Для того, чтобы добавить настройки ролей из скрипта, выполним его из директории /protected (предварительно в настройках консоли Yii надо прописать настройки доступа к базе данных и настройки авторизации - всё как в основном файле настройки):
yiic access addRules
Чтобы применить настройки ролей к созданным пользователям:
yiic access assignUsers
В результате работы скрипта таблицы AuthAssignment, AuthItem и AuthItemChild заполнятся соответствующими данными.Такие настройки авторизации подходят в том случае, если правила поведения и состав пользователей системы меняются редко. В этом случае нет особой необходимости в форме заведения новых пользователей (хотя лучше сделать; с доступом только администратору), в форме управления правами доступа.
Комментарии
Отправить комментарий