【问题标题】:Yii, best way to implement "user change of password"Yii,实现“用户更改密码”的最佳方式
【发布时间】:2012-10-25 09:22:51
【问题描述】:

我正在使用 Yii 进行应用程序,我正在编写一个非常简单的用户管理,例如注册,删除和更新用户...对于更新现有用户,我需要先检查旧密码,然后再将其更改为新插入的密码。所以这是我在表单中的字段:

username:----
old_password:---
new_password:---

我的用户表如下所示:

id, username, password

如何在使用 new_password 更新 old_password 之前验证它?我知道通常的 php 编码,但我想知道是否有任何 Yii 技巧可以自动执行此操作...

提前致谢

【问题讨论】:

  • 您应该尽可能重用现有的身份验证框架,因为它确实很复杂。例如,看看github.com/delight-im/PHP-Auth,它既与框架无关,也与数据库无关。

标签: php authentication yii user-management


【解决方案1】:

创建一个具有更新传递逻辑的action 很简单。

form 的目标设为新的action,在这种情况下为actionChangePassvalidate,按照你想要的方式。

粗略的例子可以这样放

    public function actionChangePass($id)
    {  
    $user = loadModel($id)
    if(md5($_POST['User']['old_password']) === $user->password)
    {
       $user->setScenario('changePassword');
       $user->attributes = $_POST['User'];                
       $user->password = md5($_POST['User']['new_password']);
       if($user->save())
         Yii::app()->user->setFlash('passChanged', 'Your password has been changed <strong>successfully</strong>.');
    }            
    else
    {
      Yii::app()->user->setFlash('passChangeError', 'Your password was not changed because it did not matched the <strong>old password</strong>.');                    
    }  
 }

还要确保您的用户 User Model 中有 $old_password。您还可以在模型规则中进行一些验证以使新密码成为必需的

也可以有一些不同的方法,但我是这样做的

同时创建您的自定义验证 scenario changePassword

【讨论】:

  • 不是真的... Yiish 将创建一个新表单并将所有逻辑放入其中
  • @ThomasVdBerge 它与视图无关,因为表单在视图中。操作很简单,您可以创建新表单并在一天结束时重定向到该操作,该操作必须完成工作
  • 我更喜欢创建新的模型表单,我不想用虚幻的字段属性弄脏我的模型。
  • @ThomasVdBerge 你能提供一个 yii2sh 的工作示例吗?
【解决方案2】:

这是我个人喜欢做的事情。这是一个复杂的版本。 向模型中添加两​​个有助于处理密码的字段。请注意,这两个字段在数据库中不存在,也不存在于 Gii 生成的代码中。类似的东西

class UserModel extends CActiveRecord
{
    /*Password attributes*/
    public $initial_password;
    public $repeat_password;
    //..................
}

在表单中,不要将数据库中的实际密码字段与任何输入相关联。数据库中的两个字段应该与这两个字段相关联。表单的简短版本变为:

    <?php echo $form->errorSummary($model); ?>


    <?php echo $form->passwordFieldRow($model,'initial_password',array('class'=>'span5','maxlength'=>128)); ?> 

    <?php echo $form->passwordFieldRow($model,'repeat_password',array('class'=>'span5','maxlength'=>128)); ?>  

现在我如何知道用户更改了密码?如果两个字段为空,我只需检查 beforeSave() 并比较它们,然后更改密码。如果它们是空的,那么我将完全跳过整个过程。如此简单的 beforeSave 版本是:

/**
     * Called before saving the model
     */
    protected function beforeSave()
    {
        if(parent::beforeSave())
        { 
            if($this->isNewRecord)
            { 
                $this->password = HashYourPass($this->initial_password); 
            }
            else
                { 
                    //should we update password?
                    if($this->initial_password !== '')
                    {
                        //encrypt password and assign to password field
                        $this->password = HashYourPass($this->initial_password);
                       //Check old password match here
                    }
                }
            return true;
        }
        else
            return false;
    }

现在根据您的问题,缺少一件事。检查旧密码!您可以添加称为旧密码的新模型字段及其表单输入控件。然后在 beforesave 方法中(如注释所示),您可以将输入与数据库中的实际密码字段进行比较,如果它们匹配,则更改密码。

您可以将它们作为验证规则添加到场景中,但我发现它有点复杂,而且我几乎没有时间就采用了这种方法。

【讨论】:

    【解决方案3】:

    您不应该用垃圾污染您的模型。请始终牢记这些基本的 MVC 原则:

    • 您的控制器必须不知道您的模型的实现。
    • 不要用与您的应用程序业务模型无关的东西污染您的模型。

    始终创建可重用的代码,让您的代码“干燥”(不要重复自己)

    顺便问一下,用户名字段的用途是什么?由于表单只对登录的用户可用,用户名可以通过 Yii::app()->user 访问。

    <?php
    // models/ChangePasswordForm.php
    
    class ChangePasswordForm extends CFormModel
    {
        /**
         * @var string
         */
        public $currentPassword;
    
        /**
         * @var string
         */
        public $newPassword;
    
        /**
         * @var string
         */
        public $newPasswordRepeat;
    
        /**
         * Validation rules for this form.
         *
         * @return array
         */
        public function rules()
        {
            return array(
                array('currentPassword, newPassword, newPasswordRepeat', 'required'),
                array('currentPassword', 'validateCurrentPassword', 'message'=>'This is not your password.'),
                array('newPassword', 'compare', 'compareAttribute'=>'validateNewPassword'),
                array('newPassword', 'match', 'pattern'=>'/^[a-z0-9_\-]{5,}/i', 'message'=>'Your password does not meet our password complexity policy.'),
            );
        }
    
        /**
         * I don't know your hashing policy, so I assume it's simple MD5 hashing method.
         * 
         * @return string Hashed password
         */
        protected function createPasswordHash($password)
        {
            return md5($password);
        }
    
        /**
         * I don't know how you access user's password as well.
         *
         * @return string
         */
        protected function getUserPassword()
        {
            return Yii::app()->user->password;
        }
    
        /**
         * Saves the new password.
         */
        public function saveNewPassword()
        {
            $user = UserModel::findByPk(Yii::app()->user->username);
            $user->password = $this->createPasswordHash($this->newPassword);
            $user->update();
        }
    
        /**
         * Validates current password.
         *
         * @return bool Is password valid
         */
        public function validateCurrentPassword()
        {
            return $this->createPasswordHash($this->currentPassword) == $this->getUserPassword();
        }
    }
    

    示例控制器操作:

    public function actionChangePassword()
    {
        $model=new ChangePasswordForm();
        if (isset($_POST['ChangePasswordForm'])) {
            $model->setAttributes($_POST['ChangePasswordForm']);
            if ($model->validate()) {
                $model->save();
                // you can redirect here
            }
        }
    
        $this->render('changePasswordTemplate', array('model'=>$model));
    }
    

    示例模板代码:

        <?php echo CHtml::errorSummary($model); ?>
    
        <div class="row">
            <?php echo CHtml::activeLabel($model,'currentPassword'); ?>
            <?php echo CHtml::activePasswordField($model,'currentPassword') ?>
        </div>
    
        <div class="row">
            <?php echo CHtml::activeLabel($model,'newPassword'); ?>
            <?php echo CHtml::activePasswordField($model,'newPassword') ?>
        </div>
    
        <div class="row">
            <?php echo CHtml::activeLabel($model,'newPasswordRepeat'); ?>
            <?php echo CHtml::activePasswordField($model,'newPasswordRepeat') ?>
        </div>
    
        <div class="row submit">
            <?php echo CHtml::submitButton('Change password'); ?>
        </div>
    
        <?php echo CHtml::endForm(); ?>
    </div><!-- form -->
    

    模板应该很容易创建。这段代码经过一些细微的调整,可以复制并粘贴到另一个 Yii 项目中。

    【讨论】:

    • 我用示例模板代码更新了帖子。您应该遵循 Yii 官方教程,了解如何在视图中管理表单。
    猜你喜欢
    • 1970-01-01
    • 2011-03-26
    • 1970-01-01
    • 1970-01-01
    • 2021-04-25
    • 2021-04-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多