Курс по Yii с нуля. Урок 4. Дорабатываем простую работу с пользователями: хранение пароля при редактировании пользователя.

Курс по Yii с нуля. Урок 4. Дорабатываем простую работу с пользователями: хранение пароля при редактировании пользователя. Настраиваем правильное сохранение пароля при редактировании профиля пользователя. Больше не выводим хэш пароля в форму редактирования.

Начнём этот урок с доработки одного важного и интересного момента, который могли заметить те, кто проделывал все действия 3-го урока. А именно редактирование профиля пользователя. Откройте из бокового меню Manage User -> иконку редактирование пользователя (либо сразу ссылку - http://blog:8888/user/update?id=1) и вы увидите форму с корявостью в поле пароля:

Yii избавиться от кучи звёздочек в поле пароля при редактировании пользователя, хэширование пароля

Мы видим куеву кучу точек (звёздочек) скрывающих пароль. Тот факт, что наш пароль содержит 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'а.



Другие статьи по этой теме:
  1. 14 Разработка приложения на Yii. Урок 14: Выводим список категорий как новый виджет на сайте (29.04.2015) free
  2. 13 Разработка приложения на Yii. Урок 13: Внедряем категории для статей. (29.04.2015) free
  3. 12 Разработка приложения на Yii. Урок 12: Профилирование приложения, включаем кеширование. (20.01.2015)
  4. 11 Yiico. Видеокурс по разработке сайта на Yii. Урок 11: Отладка приложения, включаем журналирование. (20.01.2015)
  5. 10 Yiico. Видеокурс по разработке сайта на Yii. Урок 10: Если ваше приложение находится не в корневой папке, а во вложенной. (19.10.2014) free
  6. 9 Разработка сайта на Yii с нуля. Урок 9. Выборка статей определённого автора. (13.08.2014) free
  7. 8 Разработка сайта на Yii с нуля. Урок 8. Вызов в моделях функции, общей для них. Как избегать дублирования кода? (25.07.2014) free
  8. 7 Разработка сайта на Yii с нуля. Урок 7. Изменение количества выводимых записей на странице в CGridView. Включаем сессии Yii. (04.09.2013) free
  9. 6 Разработка сайта на Yii с нуля. Урок 6. Автоматич. отправка оповещений об одобренных комментариях на email автора комментария (11.08.2013) free
  10. 5 Разработка сайта на Yii с нуля. Урок 5. Переименовываем blog в yiico. Изменяем "Home" в breadcrumbs. Включаем Gzip-сжатие. (09.08.2013) free
  11. 4 Курс по Yii с нуля. Урок 4. Дорабатываем простую работу с пользователями: хранение пароля при редактировании пользователя. (13.04.2013) ← вы тут free
  12. 3 Курс по Yii с нуля. Урок 3. Создаём новых пользователей. Организуем простую систему авторизации. Аутентификация, пароли, соли. (20.07.2014) free
  13. 2 Курс по Yii с нуля. Урок 2. Переносим и настраиваем Yii и проект нашего сайта на рабочем сервере. Избавляемся от index.php в url (09.07.2014) free
  14. 1 Курс по Yii с нуля. Урок 1. Устанавливаем Yii на локальном компьютере. Заводим проект будущего сайта. (10.03.2013) free

Комментарии (2)     Подпишитесь на RSS комментариев к этой статье.

2 комментариев

#730
Саша говорит:
December 21, 2012 at 03:59 pm
а если просто к форме прибавить 'value'=>($update || !$_POST) ? '' : $model->password));
#807
John Connor говорит:
March 20, 2013 at 10:39 pm
Сейчас вроде как последний писк это https://github.com/phpnode/YiiPassword