Курс по Yii с нуля. Урок 4. Дорабатываем простую работу с пользователями: хранение пароля при редактировании пользователя.
Начнём этот урок с доработки одного важного и интересного момента, который могли заметить те, кто проделывал все действия 3-го урока. А именно редактирование профиля пользователя. Откройте из бокового меню Manage User -> иконку редактирование пользователя (либо сразу ссылку - http://blog:8888/user/update?id=1) и вы увидите форму с корявостью в поле пароля:
Мы видим куеву кучу точек (звёздочек) скрывающих пароль. Тот факт, что наш пароль содержит 8 символов, уже наводит на подозрения. И, действительно, в это поле попадает всё содержимое поля password из таблицы tbl_user. А там записан не сам пароль, а хэш этого пароля.
Что такое хэш?
В данном случае это пароль в закодированном виде. Он обработан функцией преобразования в строку символов (hashPassword), каждый символ пароля дробится и представляется несколькими символами. Поэтому в поле пароля не 8, а куча точек. Точнее говоря, у нас ещё у нас конкатенируется соль к паролю, и уже потом преобразовывается.
Правильно, принять точку зрения, что при редактировании профиля мы вообще не должны получать значение в поле пароля, то есть там должно быть всё пусто (захотим поменять пароль – введём туда новое значение, не захотим – не будем ничего писать и тогда пароль останется прежним; вот какой логики будем держаться).
Тогда делаем изменения в модели User.php (согласно совету Елисеева Дмитрия - см. ссылку в конце урока).
class User extends CActiveRecord { public $new_password; public $new_confirm; /** * Returns the static model of the specified AR class. * @return CActiveRecord the static model class */ public static function model($className=__CLASS__) { return parent::model($className); } /** * @return string the associated database table name */ public function tableName() { return '{{user}}'; } /** * @return array validation rules for model attributes. */ public function rules() { // NOTE: you should only define rules for those attributes that // will receive user inputs. return array( array('username, email', 'required'), array('username', 'match', 'pattern'=>'#^[a-zA-Z0-9_\.-]+$#', 'message'=>'Логин содержит запрещённые символы'), array('email', 'email', 'message'=>'Неверный формат E-mail адреса'), array('username, email', 'unique', 'caseSensitive'=>false), array('username, new_password, new_confirm, salt, email', 'length', 'max'=>128), array('email, username', 'unique'), array('new_password', 'length', 'min'=>6, 'allowEmpty'=>true), array('new_confirm', 'compare', 'compareAttribute'=>'new_password', 'message'=>'Пароли не совпадают'), array('profile', 'safe'), // Register array('new_password', 'required', 'on'=>'register'), ); } /** * @return array relational rules. */ public function relations() { // NOTE: you may need to adjust the relation name and the related // class name for the relations automatically generated below. return array( 'posts' => array(self::HAS_MANY, 'Post', 'author_id'), ); } /** * @return array customized attribute labels (name=>label) */ public function attributeLabels() { return array( 'id' => 'Id', 'username' => 'Username', 'new_password' => 'Новый пароль', 'new_confirm' => 'Подтвердите новый пароль', 'salt' => 'Salt', 'email' => 'Email', 'profile' => 'Profile', ); } protected function beforeSave() { if ($this->new_password) { $this->salt = self::generateSalt(); $this->password = $this->hashPassword($this->new_password, $this->salt); } return parent::beforeSave(); } // После валидации присваиваем пароль и соль. /*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; } */
Важно: не забудьте в контроллере UserController.php дописать сценарий 'register' (а то будет возможным создание нового пользователя без задания пароля) - в методе actionCreate() в строке $model=new User('register');
Мы заменили password_repeat на new_confirm. Это необязательно, но смысл добавки _repeat теряется, так как он работает если оставлять поле password, а мы ввели новое поле new_password (его используем теперь вместо password), сделав поле password необязательным (оно задействуется только в beforeSave()) и перестали использовать afterValidate(), вместо которого – beforeSave(). Как подсказал Дмитрий если сохранять без валидации, указывая "false" в $user->save(false)
, то beforeValidate и afterValidate не сработают. А "beforeSave() надёжнее, так как сработает почти в любом случае".
Поэтому теперь в rules() необходимо указывать атрибут, с которым сравнивать new_confirm: строка array('new_confirm', 'compare', 'compareAttribute'=>'new_password', 'message'=>'Пароли не совпадают'),
вместо прежней array('new_confirm', 'compare'),
Дальше в представлении views/user/_form.php используем new_password вмеcто password и new_confirm вместо password_repeat.
<div class="row"> <?php echo $form->labelEx($model,'new_password'); ?> <?php echo $form->passwordField($model,'new_password',array('size'=>60,'maxlength'=>128)); ?> <?php echo $form->error($model,'new_password'); ?> </div> <div class="row"> <?php echo $form->label($model,'new_confirm'); ?> <?php echo $form->passwordField($model,'new_confirm',array('size'=>60,'maxlength'=>128)); ?> <?php echo $form->error($model,'new_confirm'); ?> </div>
Так мы избавились от двойного генерирования пароля из прошлого урока (об этом баге писали в комментариях), и достигли большую защищённость, потому что содержимое password не выводится в форме, и также теперь нет необходимости генерировать пароль, если его не изменяем.
Логика поправлена. Выражаю благодарность Елисееву Дмитрию (www.elisdn.ru)
Скачать файлы рабочего проекта после 4 урока (блог + база данных). (доступ: admin – adminadmin и demo – demodemo)
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
2 комментариев