Курс по Yii с нуля. Урок 3. Создаём новых пользователей. Организуем простую систему авторизации. Аутентификация, пароли, соли.
В Yii блоге, который мы установили по умолчанию, и настроили в 2-х предыдущих уроках, уже модель User (связана с таблицей tbl_user), но ни контроллера, ни файлов видов ещё не создано, а в базе - только один бедняжка "demo". Есть что развивать.
1) С помощью Gii создадим для модели User свою Crud. (Так за секунды мы получим контроллер с необходимыми функциями работы с пользователями + все файлы видов).
Если у вас пока не включен Gii, то надо включить его в работу, прописав в config/main.php:
'modules'=>array( // uncomment the following to enable the Gii tool 'gii'=>array( 'class'=>'system.gii.GiiModule', 'password'=>'yourpassword', // If removed, Gii defaults to localhost only. Edit carefully to taste. 'ipFilters'=>array('127.0.0.1', '::1'), ), ),
2) При попытке открыть /index.php/user, выпадает ошибка 500 (говорит, что нет search в модели).
Не проблема. Возьмём этот метод из модели Post. И изменим, что надо и добавим в models/User.php:
public function search() { $criteria=new CDbCriteria; $criteria->compare('username',$this->username,true); $criteria->compare('email',$this->email); return new CActiveDataProvider('User', array( 'criteria'=>$criteria, 'sort'=>array( 'defaultOrder'=>'username, email DESC', ), )); }
3) Теперь закомментируем временно accessRules() в контроллер UserController или разрешим demo функции администраторские (потому что этот demo пока у нас один и мы на него возлагаем всю работу).
Создаём от его лица нового пользователя 'admin' (через путь 'index.php/user/create'). Видим что у нас просят зачем-то Salt (надо чтобы сама генерировалась), и кроме того, пароль не кодируется, а сохраняется в базу как мы его ввели. Это надо доработать.
4) В User::rules() дописываем проверку на уникальность email и username:
public function rules() { // NOTE: you should only define rules for those attributes that // will receive user inputs. return array( ... array('email, username', 'unique'), // The following rule is used by search(). // Please remove those attributes that should not be searched. array('id, email, username, password', 'safe', 'on'=>'search'), ); }
5) Удалим из protected/views/user/_form поле 'salt' и добавим поле для повтора пароля
<div class="row"> <?php echo $form->label($model,'password_repeat'); ?> <?php echo $form->passwordField($model,'password_repeat',array('size'=>60,'maxlength'=>256)); ?> <?php echo $form->error($model,'password_repeat'); ?> </div>
Это обычная практика, когда нового пользователя при регистрации просят ввести пароль повторно, чтобы он не ошибся. Встроенный в Yii класс CCompareValidator поможет нам сравнить пароли в двух полях.
Добавляем в модель User в самый верх переменную $password_repeat:
<?php
class User extends CActiveRecord
{
public $password_repeat;
...
Мы добавляем в названии арибута _repeat, потому что валидатор так работает. Если он не находит явно указанного поля, с которым производить сравнение, то сравнит с полем такого же названия с добавкой _repeat.
Теперь добавим в User::rules() правило compare, и пропишем password_repeat в безопасные атрибуты, чтобы он мог передаваться при вызове setAttributes(), хотя он и не является полем в таблице tbl_user:
array('password', 'compare'), array('profile, password_repeat', 'safe'),
6) Вернёмся к закодированию пароля при добавлении в базу данных. Сейчас он не кодируется никак и это небезопасно. Но и тут всё относительно просто: нам поможет метод afterValidate(). В модели Users уже нам разработчики заготовили функции для шифрования, можно написать свои, но я пока оставляю как есть, только добавляю afterValidate():
// После валидации присваиваем пароль и соль. public function afterValidate() { $this->password = self::hashPassword($this->password, $this->salt); if($this->isNewRecord) { $salt = self::generateSalt(); $this->password = self::hashPassword($this->password, $salt); $this->salt = $salt; //$this->role = 'user'; } return true; } // Проверка валидности пароля public function validatePassword($password) { return $this->hashPassword($password,$this->salt)===$this->password; } // Создание хэша пароля public function hashPassword($password,$salt) { return md5($salt.$password); } /** * Generates a salt that can be used to generate a password hash. * @return string the salt */ protected function generateSalt() { return uniqid('',true); }
ВНИМАНИЕ: вместо afterValidate() лучше использовать beforeSave(), в след. уроке мы делаем эту замену, здесь для первого общего понимания оставим afterValidate().
Тут соль генерируется как это сделано по-умолчанию, с помощью функции uniqid(). Но функция генерации соли может быть например, как предлагает timlar на форуме yiiframework.ru
// Генерация "соли". Этот метод генерирует случайным образом слово // заданной длины. Длина указывается в единственном свойстве метода. // Символы, применяемые при генерации, указаны в переменной $chars. // По умолчанию, длина соли 32 символа. public function generateSalt($length=32) { $chars = "abcdefghijkmnopqrstuvwxyz023456789"; srand((double)microtime()*1000000); $i = 1; $salt = '' ; while ($i <= $length) { $num = rand() % 33; $tmp = substr($chars, $num, 1); $salt .= $tmp; $i++; } return $salt; }
Ещё мы немного изменили для кратости метод authenticate в компоненте UserIdentity, посмотрите:
public function authenticate() { $user=User::model()->find('LOWER(username)=?',array(strtolower($this->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->errorCode=self::ERROR_NONE; } return !$this->errorCode; }
Цель достигнута, не забудьте восстановить accessRules(), и указать там в правах нужных пользователей. Мы не вводили роли пользователям, пока по простому, для больших приложений удобнее будет взять расширения (например yii-users, yii-user-management).
И добавьте в шаблон, например в column2.php
<?php $this->beginWidget('zii.widgets.CPortlet', array( 'title'=>'Operations', )); $this->widget('zii.widgets.CMenu', array( 'items'=>$this->menu, 'htmlOptions'=>array('class'=>'operations'), )); $this->endWidget(); ?>
Это покажет меню, созданные Gii. А в общее меню (компонент userMenu.php) добавим ссылку на управление пользователями:
<li><?php echo CHtml::link('Manage Users',array('user/admin'), $htmlOptions=array('class'=>'admin')); ?></li>
До следующего урока, друзья!
almix
Разработчик Loco, автор статей по веб-разработке на Yii, CodeIgniter, MODx и прочих инструментах. Создатель Team Sense.
Вы можете почитать все статьи от almix'а.
- 14 Разработка приложения на Yii. Урок 14: Выводим список категорий как новый виджет на сайте (29.04.2015) free
- 13 Разработка приложения на Yii. Урок 13: Внедряем категории для статей. (29.04.2015) free
- 12 Разработка приложения на Yii. Урок 12: Профилирование приложения, включаем кеширование. (20.01.2015)
- 11 Yiico. Видеокурс по разработке сайта на Yii. Урок 11: Отладка приложения, включаем журналирование. (20.01.2015)
- 10 Yiico. Видеокурс по разработке сайта на Yii. Урок 10: Если ваше приложение находится не в корневой папке, а во вложенной. (19.10.2014) free
- 9 Разработка сайта на Yii с нуля. Урок 9. Выборка статей определённого автора. (13.08.2014) free
- 8 Разработка сайта на Yii с нуля. Урок 8. Вызов в моделях функции, общей для них. Как избегать дублирования кода? (25.07.2014) free
- 7 Разработка сайта на Yii с нуля. Урок 7. Изменение количества выводимых записей на странице в CGridView. Включаем сессии Yii. (04.09.2013) free
- 6 Разработка сайта на Yii с нуля. Урок 6. Автоматич. отправка оповещений об одобренных комментариях на email автора комментария (11.08.2013) free
- 5 Разработка сайта на Yii с нуля. Урок 5. Переименовываем blog в yiico. Изменяем "Home" в breadcrumbs. Включаем Gzip-сжатие. (09.08.2013) free
- 4 Курс по Yii с нуля. Урок 4. Дорабатываем простую работу с пользователями: хранение пароля при редактировании пользователя. (13.04.2013) free
- 3 Курс по Yii с нуля. Урок 3. Создаём новых пользователей. Организуем простую систему авторизации. Аутентификация, пароли, соли. (20.07.2014) ← вы тут free
- 2 Курс по Yii с нуля. Урок 2. Переносим и настраиваем Yii и проект нашего сайта на рабочем сервере. Избавляемся от index.php в url (09.07.2014) free
- 1 Курс по Yii с нуля. Урок 1. Устанавливаем Yii на локальном компьютере. Заводим проект будущего сайта. (10.03.2013) free
14 комментариев
<?php echo $form->passwordField($model,'password',array('size'=>60,'maxlength'=>128,'value'=>'')); ?>
нужно сбрасывать пароли, то там хэш при неудачной валидации забит
Loco: Верно, но некритично.
я делал регистрацию ручную, то есть только админы заводят новых пользователей. А так, да, разрешаете нужные экшены в контроллере для нужных пользователей.
Что в выделенной функции вы хотите сказать?
При добавлении пользователя пароль генерится дважды .
public function afterValidate()
{
if($this->isNewRecord) {
$salt = self::generateSalt();
$this->parent_id = (Yii::app()->user->parent_id==0?Yii::app()->user->id:Yii::app()->user->parent_id);
$this->password = self::hashPassword($this->password, $salt);
$this->salt = $salt;
//$this->role = 'user';
return true;
}
$this->password = self::hashPassword($this->password, $this->salt);
return true;
}
Господа.
Можно сказать впервый взялся за YII.
Делаю регу пользователей. По вашей статье добавил ввод повторно пароля. теперь форма реги, пишет что поле (password_repeat) не может быть пустым. при чем весгда. Даже когда оно зааолнено. код тот же что и у Вас.