7

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

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

我的用户表如下所示:

id, username, password

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

提前致谢

4

3 回答 3

9

你不应该用垃圾污染你的模型。请始终牢记这些基本的 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 项目中。

于 2013-02-17T22:38:02.057 回答
4

它的简单创建action具有更新传递的逻辑。

在这种情况下将目标form设为新的, 并以您想要的方式进行。actionactionChangePassvalidate

可以这样举一个粗略的例子

    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 中有 $old_password User Model。您也可以在模型规则中进行一些验证以使新密码成为必需

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

还创建您的自定义验证scenario changePassword

于 2012-11-05T15:02:59.260 回答
1

这是我个人喜欢做的事情。这是一个复杂的版本。向模型中添加两​​个有助于处理密码的字段。请注意,这两个字段在数据库中不存在,也不存在于 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 方法中(如注释所示),您可以将输入与数据库中的实际密码字段进行比较,如果它们匹配,则更改密码。

您可以将它们添加为带有场景的验证规则,但我发现它在某种程度上很复杂,而且我几乎没有时间就采用了这种方法。

于 2012-11-05T15:04:29.293 回答