This is an old revision of the document!
Yii 2 Basic Application Template
Improved Password Security
By default, the basic template comes with plain text password support in file @app/models/User.php
. To improve this to use a password hash with salt, we must do some changes.
Model file @app/models/User
class User extends \yii\base\Object implements \yii\web\IdentityInterface { public $id; public $username; //public $password; // Remove plain password support public $authKey; public $accessToken; public $passwordHash; // Use password hash. Generated like... password_hash("User'sPassword", PASSWORD_DEFAULT); private static $users = [ '100' => [ 'id' => '100', 'username' => 'admin', 'authKey' => 'test100key', 'accessToken' => '100-token', 'passwordHash' => '$2y$10$/lVWm8iL07.zoBE.7nM8ueDSPiR8XwxyoAuZPfCclPZ3PscOXM.KK' // 123admin ], ... ]; /** * Find username for specified userid. * * @id integer $id of user to search. * @return string Username if found, 'N/A' if not found. */ public static function findUsername($id) { $usr = isset(self::$users[$id]) ? new static(self::$users[$id]) : null; if (count($usr) > 0) { return $usr->username; } else { return 'N/A'; } } ... /** * Validates password * * @param string $password password to validate * @return boolean if password provided is valid for current user */ public function validatePassword($password) { //return $this->password === $password; // disable plain password support return password_verify($password, $this->passwordHash); // enable password hash support } }
Model file @app/models/PasswordForm
<?php namespace app\models; use Yii; use yii\base\Model; /** * LoginForm is the model behind the login form. */ class PasswordForm extends Model { //public $username; public $password; public $encrypted_password; //public $rememberMe = true; //private $_user = false; /** * @return array the validation rules. */ public function rules() { return [ [['encrypted_password'], 'safe'], // password required [['password'], 'required'], // password is validated by validatePassword() ['password', 'validatePassword'], ]; } /** * Validates the password. * This method serves as the inline validation for password. * * @param string $attribute the attribute currently being validated * @param array $params the additional name-value pairs given in the rule */ public function validatePassword($attribute, $params) { if ($this->hasErrors()) { $this->addError($attribute, 'Invalid or unsupported password.'); } } public function encrypt() { if ($this->validate()) { return password_hash($this->password, PASSWORD_DEFAULT); // hash //return $this->password; // plain } return false; } }
Password generation view. This is a tool to help generate passwords for the User model. Copy the password here and enter it in file @app/models/User.php
as a passworHash for the required user. Eg:
'passwordHash' => '$2y$10$/lVWm8iL07.zoBE.7nM8ueDSPiR8XwxyoAuZPfCclPZ3PscOXM.KK' // 123admin
View @app/views/site/password
<?php /* @var $this yii\web\View */ /* @var $form yii\bootstrap\ActiveForm */ /* @var $model app\models\PasswordForm */ use yii\helpers\Html; use yii\bootstrap\ActiveForm; $this->title = 'Password Encryption'; $this->params['breadcrumbs'][] = $this->title; ?> <div class="site-password"> <?php if (!empty($encrypted_password)) : ?> <div class="alert alert-success" role="alert"> <strong>Encrypted Password:</strong><pre><?= $encrypted_password ?></pre> </div> <?php endif; ?> <h1><?= Html::encode($this->title) ?></h1> <p>Enter a password to encrypt:</p> <?php $form = ActiveForm::begin([ 'id' => 'login-form', 'options' => ['class' => 'form-horizontal'], 'fieldConfig' => [ 'template' => "{label}\n<div class=\"col-lg-3\">{input}</div>\n<div class=\"col-lg-8\">{error}</div>", 'labelOptions' => ['class' => 'col-lg-1 control-label'], ], ]); ?> <?= $form->field($model, 'password')->passwordInput() ?> <div class="form-group"> <div class="col-lg-offset-1 col-lg-11"> <?= Html::submitButton('Encrypt', ['class' => 'btn btn-primary', 'name' => 'encrypt-button']) ?> </div> </div> <?php ActiveForm::end(); ?> </div>
View @app/views/layout/main
to call password
view:
echo Nav::widget([ 'options' => ['class' => 'navbar-nav navbar-right'], 'items' => [ ['label' => 'Home', 'url' => ['/site/index']], // Admin menu only !Yii::$app->user->isGuest && Yii::$app->user->identity->username === 'admin' ? ['label' => 'Admin', 'url' => ['/site/admin'], 'items' => [ ... ['label' => 'Encrypt User Password', 'url' => ['/site/password']], ]] : '', ], ]); NavBar::end(); ?>
Controller @app/controllers/SiteController
to display password
view:
use app\models\PasswordForm; ... class SiteController extends Controller { public function behaviors() { return [ 'access' => [ 'class' => AccessControl::className(), 'rules' => [ [ 'actions' => [..., 'password'], 'allow' => true, 'roles' => ['@'], // @ = Authenticated users ], ... ], ], ... ]; } ... public function actionPassword() { $encrypted_password = ''; $model = new PasswordForm(); if ($model->load(Yii::$app->request->post()) && $model->encrypt()) { Yii::$app->session->setFlash('Password encrypted'); $encrypted_password = $model->encrypt(); } return $this->render('password', [ 'model' => $model, 'encrypted_password' => $encrypted_password, ]); } }