From 90ed776296bfba09b996569b6c3d3a94a79757cd Mon Sep 17 00:00:00 2001 From: Alexander Makarov Date: Thu, 18 Jul 2013 03:09:41 +0400 Subject: [PATCH] implemented password reset --- apps/advanced/common/config/params.php | 1 + apps/advanced/common/models/User.php | 12 +++-- .../console/migrations/m130524_201442_init.php | 2 + .../frontend/controllers/SiteController.php | 36 +++++++++++++ .../frontend/models/SendPasswordResetTokenForm.php | 59 ++++++++++++++++++++++ .../frontend/views/emails/passwordResetToken.php | 16 ++++++ .../advanced/frontend/views/site/resetPassword.php | 22 ++++++++ .../views/site/sendPasswordResetTokenForm.php | 22 ++++++++ 8 files changed, 165 insertions(+), 5 deletions(-) create mode 100644 apps/advanced/frontend/models/SendPasswordResetTokenForm.php create mode 100644 apps/advanced/frontend/views/emails/passwordResetToken.php create mode 100644 apps/advanced/frontend/views/site/resetPassword.php create mode 100644 apps/advanced/frontend/views/site/sendPasswordResetTokenForm.php diff --git a/apps/advanced/common/config/params.php b/apps/advanced/common/config/params.php index c381cb0..abb8873 100644 --- a/apps/advanced/common/config/params.php +++ b/apps/advanced/common/config/params.php @@ -6,6 +6,7 @@ Yii::setAlias('backend', __DIR__ . '/../../backend'); return array( 'adminEmail' => 'admin@example.com', + 'supportEmail' => 'support@example.com', 'components.cache' => array( 'class' => 'yii\caching\FileCache', diff --git a/apps/advanced/common/models/User.php b/apps/advanced/common/models/User.php index 25be085..df1d6b0 100644 --- a/apps/advanced/common/models/User.php +++ b/apps/advanced/common/models/User.php @@ -12,6 +12,7 @@ use yii\web\Identity; * @property integer $id * @property string $username * @property string $password_hash + * @property string $password_reset_token * @property string $email * @property string $auth_key * @property integer $role @@ -66,7 +67,7 @@ class User extends ActiveRecord implements Identity public function validateAuthKey($authKey) { - return $this->auth_key === $authKey; + return $this->getAuthKey() === $authKey; } public function validatePassword($password) @@ -84,7 +85,7 @@ class User extends ActiveRecord implements Identity array('email', 'filter', 'filter' => 'trim'), array('email', 'required'), array('email', 'email'), - array('email', 'unique', 'message' => 'This email address has already been taken.'), + array('email', 'unique', 'message' => 'This email address has already been taken.', 'on' => 'signup'), array('password', 'required'), array('password', 'string', 'min' => 6), @@ -96,16 +97,17 @@ class User extends ActiveRecord implements Identity return array( 'signup' => array('username', 'email', 'password'), 'login' => array('username', 'password'), + 'resetPassword' => array('password'), ); } public function beforeSave($insert) { if (parent::beforeSave($insert)) { + if (($this->isNewRecord || $this->getScenario() === 'resetPassword') && !empty($this->password)) { + $this->password_hash = SecurityHelper::generatePasswordHash($this->password); + } if ($this->isNewRecord) { - if (!empty($this->password)) { - $this->password_hash = SecurityHelper::generatePasswordHash($this->password); - } $this->auth_key = SecurityHelper::generateRandomKey(); } return true; diff --git a/apps/advanced/console/migrations/m130524_201442_init.php b/apps/advanced/console/migrations/m130524_201442_init.php index a5e9d30..e7b9e84 100644 --- a/apps/advanced/console/migrations/m130524_201442_init.php +++ b/apps/advanced/console/migrations/m130524_201442_init.php @@ -12,7 +12,9 @@ class m130524_201442_init extends \yii\db\Migration $this->createTable('tbl_user', array( 'id' => Schema::TYPE_PK, 'username' => Schema::TYPE_STRING.' NOT NULL', + 'auth_key' => Schema::TYPE_STRING.'(32) NOT NULL', 'password_hash' => Schema::TYPE_STRING.' NOT NULL', + 'password_reset_token' => Schema::TYPE_STRING.'(32)', 'email' => Schema::TYPE_STRING.' NOT NULL', 'role' => 'tinyint NOT NULL DEFAULT 10', diff --git a/apps/advanced/frontend/controllers/SiteController.php b/apps/advanced/frontend/controllers/SiteController.php index 7fce71c..44a7fd9 100644 --- a/apps/advanced/frontend/controllers/SiteController.php +++ b/apps/advanced/frontend/controllers/SiteController.php @@ -7,6 +7,8 @@ use yii\web\Controller; use common\models\LoginForm; use frontend\models\ContactForm; use common\models\User; +use yii\web\HttpException; +use frontend\models\SendPasswordResetTokenForm; class SiteController extends Controller { @@ -74,4 +76,38 @@ class SiteController extends Controller 'model' => $model, )); } + + public function actionResetPassword($token = null) + { + if ($token) { + $model = User::find(array( + 'password_reset_token' => $token, + 'status' => User::STATUS_ACTIVE, + )); + + if (!$model) { + throw new HttpException(400, 'Wrong password reset token.'); + } + + $model->scenario = 'resetPassword'; + if ($model->load($_POST) && $model->save()) { + // TODO: confirm that password was successfully saved + $this->redirect('index'); + } + + $this->render('resetPassword', array( + 'model' => $model, + )); + } + else { + $model = new SendPasswordResetTokenForm(); + if ($model->load($_POST) && $model->sendEmail()) { + // TODO: confirm that password reset token was sent + $this->redirect('index'); + } + $this->render('sendPasswordResetTokenForm', array( + 'model' => $model, + )); + } + } } diff --git a/apps/advanced/frontend/models/SendPasswordResetTokenForm.php b/apps/advanced/frontend/models/SendPasswordResetTokenForm.php new file mode 100644 index 0000000..05c8f99 --- /dev/null +++ b/apps/advanced/frontend/models/SendPasswordResetTokenForm.php @@ -0,0 +1,59 @@ +validate()) { + /** @var User $user */ + $user = User::find(array( + 'email' => $this->email, + 'status' => User::STATUS_ACTIVE, + )); + if ($user) { + $user->password_reset_token = SecurityHelper::generateRandomKey(); + if ($user->save(false)) { + $view = new View(array( + 'context' => \Yii::$app->controller, + )); + + $fromEmail = \Yii::$app->params['supportEmail']; + $name = '=?UTF-8?B?' . base64_encode(\Yii::$app->name . ' robot') . '?='; + $subject = '=?UTF-8?B?' . base64_encode('Password reset for ' . \Yii::$app->name) . '?='; + $body = $view->render('/emails/passwordResetToken', array( + 'user' => $user, + )); + $headers = "From: $name <{$fromEmail}>\r\n" . + "MIME-Version: 1.0\r\n" . + "Content-type: text/plain; charset=UTF-8"; + mail($fromEmail, $subject, $body, $headers); + return true; + } + } + } + + return false; + } +} diff --git a/apps/advanced/frontend/views/emails/passwordResetToken.php b/apps/advanced/frontend/views/emails/passwordResetToken.php new file mode 100644 index 0000000..110bfbf --- /dev/null +++ b/apps/advanced/frontend/views/emails/passwordResetToken.php @@ -0,0 +1,16 @@ +context->createUrl('site/resetPassword', array('token' => $user->password_reset_token)); +?> + +Hello username)?>, + +Follow the link below to reset your password: + + \ No newline at end of file diff --git a/apps/advanced/frontend/views/site/resetPassword.php b/apps/advanced/frontend/views/site/resetPassword.php new file mode 100644 index 0000000..3216bc1 --- /dev/null +++ b/apps/advanced/frontend/views/site/resetPassword.php @@ -0,0 +1,22 @@ +title = 'Reset password'; +$this->params['breadcrumbs'][] = $this->title; +?> +

title); ?>

+ +

Please choose your new password:

+ + array('class' => 'form-horizontal'))); ?> + field($model, 'password')->passwordInput(); ?> +
+ 'btn btn-primary')); ?> +
+ diff --git a/apps/advanced/frontend/views/site/sendPasswordResetTokenForm.php b/apps/advanced/frontend/views/site/sendPasswordResetTokenForm.php new file mode 100644 index 0000000..4d8c429 --- /dev/null +++ b/apps/advanced/frontend/views/site/sendPasswordResetTokenForm.php @@ -0,0 +1,22 @@ +title = 'Request password reset'; +$this->params['breadcrumbs'][] = $this->title; +?> +

title); ?>

+ +

Please fill out your email. A link to reset password will be sent there.

+ + array('class' => 'form-horizontal'))); ?> + field($model, 'email')->textInput(); ?> +
+ 'btn btn-primary')); ?> +
+