Reputation: 385
I have the following code to reset my password via a link through email (that works fine).
In my User Controller:
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.'));
}
}
}
The Reset Password CTP file:
Resetting your password?
<?= $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() ?>
I also have the following rules regarding comparing the two passwords:
public function validatePasswords($validator)
{
$validator->add('confirmpassword', 'no-misspelling', [
'rule' => ['compareWith', 'password'],
'message' => 'The passwords are not the same.',
]);
return $validator;
}
After typing in two identical passwords for both the password & comfirmpassword fields, I get the following error:
Unknown finder method "SELECT Users.id AS
Users__id
, Users.username ASUsers__username
, Users.password ASUsers__password
, Users.email ASUsers__email
, Users.role ASUsers__role
, Users.token ASUsers__token
FROM users Users WHERE Users.token = :c0"
Upvotes: 0
Views: 5470
Reputation: 66299
There are many odd things in the code in the question so before continuing, some required reading:
These sections aught to give enough information to have a code structure that logically can work. This is mentioned because of the following code in the question:
TableRegistry::get('ControllerName')
usage - Not necessaryTable->findByToken('literal-string')
- will always return the same thing (nothing)$table->find($notAString);
- does not match the api of the find methodIt's important to recognize that fundamentally, resetting a user's password is just an edit action. Here is an example of an edit action 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);
}
There are the following steps:
These steps are the same as are required in the question scenario. Adapting the above code to the question this code becomes:
// 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.'));
}
}
It's not mentioned in the question but the above code expects the user entity to hash the password when it's set:
You are responsible for hashing the passwords before they are persisted to the database, the easiest way is to use a setter function in your User entity:
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); } } // ... }
Otherwise, the plain text password will be saved in the users table and not the hash, and login will not work.
Upvotes: 3