【问题标题】:CakePHP 3 Password ResetCakePHP 3 密码重置
【发布时间】:2016-06-26 15:46:37
【问题描述】:

我有以下代码通过电子邮件中的链接重置我的密码(效果很好)。

在我的用户控制器中:

 public function resetpw($token = null) {
        $resetpw = $this->Users->findByToken('id');
        if ($this->request->is('post')) {
            $pw = $this->request->data['password'];
            $pwtable = TableRegistry::get('Users');
            $newpw = $pwtable->find($resetpw);
            $newpw->password = $pw;
            if ($pwtable->save($newpw)) {
                 $this->Flash->success(__('Your password has been successfully updated.'));
                return $this->redirect(['action' => 'login']);
        }
            else {
                $this->Flash->error(__('Your password could not be saved. Please, try again.'));
             }
        }
    }

重置密码 CTP 文件:

重置您的密码?

<?= $this->Flash->render(); ?>
<?= $this->Form->create() ?>
    <fieldset>
        <legend><?= __('Please enter your new password.') ?></legend>
        <?= $this->Form->input('password', ['label' => 'New Password']) ?>
        <?= $this->Form->input('confirmpassword', ['type' => 'password', 'label' => 'Confirm New Password']) ?>
    </fieldset>
    <?= $this->Form->button(__('Update password')); ?>
<?= $this->Form->end() ?>

关于比较两个密码,我也有以下规则:

public function validatePasswords($validator)
{
    $validator->add('confirmpassword', 'no-misspelling', [
        'rule' => ['compareWith', 'password'],
        'message' => 'The passwords are not the same.',
    ]);
    return $validator;
}

在密码和确认密码字段输入两个相同的密码后,我收到以下错误:

未知查找方法“SELECT Users.id AS Users__id, Users.username AS Users__username,Users.password AS Users__password,Users.email AS Users__email, Users.role AS Users__role, Users.token AS Users__token FROM users Users WHERE Users.token = :c0"

【问题讨论】:

  • 我想你的意思是$this-&gt;Users-&gt;findByToken($token);我也不知道你为什么要先搜索 $this->Users,然后使用 TableRegister 获取 Users 模型的另一个实例....
  • @AD7six 基本上我试图从用户表中获取令牌数据以确定需要重置哪个用户的密码。然后获取输入的密码,在用户表中搜索用户的密码,然后覆盖它。
  • @JvO 在 CakePHP 3 Cookbook 中,更新数据的方法使用 TableRegistry & get 例如:$articlesTable = TableRegistry::get('Articles'); 然后$article = $articlesTable-&gt;get(12),其中检索到的数据的 id 为 12。我正在使用在找到 id 时生成的令牌,并且它与数据库中的关联电子邮件有关,我想知道什么是构造它的方法,以便它引用生成的令牌的 id。
  • 我知道,这是 Cookbook 样板代码。但是:在控制器 X 中,自动有一个指向模型的 $this->X。所以创建一个新对象只是在浪费内存。至于查找id:想法是按令牌搜索。它返回一个用户对象并从中获取 id:$resetpw->id。就是这样。

标签: php cakephp passwords cakephp-3.0 change-password


【解决方案1】:

序言

问题的代码中有很多奇怪的东西,所以在继续之前,需要阅读一些内容:

这些部分提供了足够的信息以具有逻辑上可以工作的代码结构。之所以提到这是因为问题中的以下代码:

  • TableRegistry::get('ControllerName') 用法 - 没有必要
  • Table-&gt;findByToken('literal-string') - 总是返回相同的东西(无)
  • $table-&gt;find($notAString); - 与find方法的api不匹配

更新字段只是一个编辑

重要的是要认识到,从根本上说,重置用户密码只是一个编辑操作。以下是编辑操作的示例taken from the blog tutorial

// src/Controller/ArticlesController.php

public function edit($id = null)
{
    $article = $this->Articles->get($id);
    if ($this->request->is(['post', 'put'])) {
        $this->Articles->patchEntity($article, $this->request->data);
        if ($this->Articles->save($article)) {
            $this->Flash->success(__('Your article has been updated.'));
            return $this->redirect(['action' => 'index']);
        }
        $this->Flash->error(__('Unable to update your article.'));
    }

    $this->set('article', $article);
}

有以下步骤:

  • 查找文章实体
  • 更新文章实体
  • 保存文章实体
  • 一些错误处理

这些步骤与问题场景中所需的步骤相同。将上面的代码改编成这个代码变成的问题:

// src/Controller/UsersController.php

public function edit($token = null)
{
    $user = $this->Users->findByToken($token)->first();
    if (!$user) {
        $this->Flash->success(__('No user with that token found.'));
        return $this->redirect('/');
    }

    if ($this->request->is(['post'])) {
        $user->password = $this->request->data['password'];
        $user->confirmpassword = $this->request->data['confirmpassword'];
        if ($this->Users->save($user)) {
            $this->Flash->success(__('Your password has been successfully updated.'));
            return $this->redirect(['action' => 'login']);
        }
        $this->Flash->error(__('Your password could not be saved. Please, try again.'));
    }
}

散列密码?

问题中没有提到,但上面的代码期望用户实体为hash the password when it's set

您有责任在密码被散列之前对其进行哈希处理 持久化到数据库,最简单的方法是使用setter函数 在您的用户实体中:

namespace App\Model\Entity;

use Cake\Auth\DefaultPasswordHasher;
use Cake\ORM\Entity;

class User extends Entity
{

    // ...

    protected function _setPassword($password)
    {
        if (strlen($password) > 0) {
          return (new DefaultPasswordHasher)->hash($password);
        }
    }

    // ...
}

否则明文密码会保存在users表中而不是hash中,无法登录。

【讨论】:

  • 谢谢,这很有帮助。我之前确实对密码进行了哈希处理,但在尝试保存新密码时仍然遇到问题:Argument 1 passed to Cake\ORM\Table::save() must be an instance of Cake\Datasource\EntityInterface, instance of Cake\ORM\Query given, called in C:\xampp\htdocs\bookmarker\src\Controller\UserController on line 189,第 189 行指的是if ($this-&gt;Users-&gt;save($user)) {
  • 所以我遇到了两个单独的问题:如果我使用更正后的代码,然后单击电子邮件中的链接,我将被重定向到主页(未找到令牌,尽管令牌中存在该用户的 SQL 表),如果我注释掉令牌检查代码(允许我输入新密码),我会收到错误:Argument 1 passed to Cake\ORM\Table::save() must be an instance of Cake\Datasource\EntityInterface, instance of stdClass given, called in C:\xampp\htdocs\bookmarker\src\Controller\UsersController.php on line 189,第 189 行再次是 if ($this-&gt;Users-&gt;save($user)) {
  • 期待听到您如何调试和修复这些问题 :) (它们似乎与此答案中的代码/逻辑无关,或者至少是 other您的应用程序逻辑预先存在的问题)。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-01-08
  • 2014-12-03
  • 2015-02-04
相关资源
最近更新 更多