Jul 7, 2009
CakePHP :: Forgotten Password
Sometimes people forget. Usually it is when they need to get into their account or behind the nice ACL system you have setup. So, how do you handle the forgotten passwords?
With our sites we have a small form setup for people to fill in their email address, that will then send them an email with a replaced password, fill in the temporary password in the database, they then can use that new password to log in and change it.
The form in the view just asks for the email address of your blank-minded user. Since it is a user account interaction with the site we use the users_controller to run everything, thus this code goes into the views/users/forgot.ctp.
1 echo $form->create('User', array('action' => 'forgot'));<br />echo $form->input('email', array('label' => ''));<br />echo $form->end('Reset Password');
Next, add the forgot method to your in your users_controller. If we find an email in our database then we shall run the createTempPassword in our user model, Auth the resulting password and send a password.
1 function forgot() {<br /> if(!empty($this->data)) {<br /> $this->User->contain();<br /> $user = $this->User->findByEmail($this->data['User']['email']);<br /> if($user) {<br /> $user['User']['tmp_password'] = $this->User->createTempPassword(7);<br /> $user['User']['password'] = $this->Auth->password($user['User']['tmp_password']);<br /> if($this->User->save($user, false)) {<br /> $this->__sendPasswordEmail($user, $user['User']['tmp_password']);<br /> $this->Session->setFlash('An email has been sent with your new password.');<br /> $this->redirect($this->referer());<br /> }<br /> } else {<br /> $this->Session->setFlash('No user was found with the submitted email address.');<br /> }<br /> }<br />}
There are two odd calls in here. The first we are calling $this->User->createTempPassword() – which is a method in the models/user.php. It looks something like this:
1 function createTempPassword($len) {<br /> $pass = '';<br /> $lchar = 0;<br /> $char = 0;<br /> for($i = 0; $i < $len; $i++) {<br /> while($char == $lchar) {<br /> $char = rand(48, 109);<br /> if($char > 57) $char += 7;<br /> if($char > 90) $char += 6;<br /> }<br /> $pass .= chr($char);<br /> $lchar = $char;<br /> }<br /> return $pass;<br />}
It returns a random string that we are saving into the users table. After that we are using the Auth component to set that string as a hashed value, that overides that old password on Save. When we save it into the database, and everything goes smooth we run the Email Component -> which sends the email address an email.
First include the Email Component in the top of your users_controller.
1 var $components = array('Email');
And then in the same controller add the following code:
1 function __sendPasswordEmail($user, $password) {<br /> if ($user === false) {<br /> debug(__METHOD__." failed to retrieve User data for user.id: {$user['User']['id']}");<br /> return false;<br /> }<br /> $this->set('user', $user['User']);<br /> $this->set('password', $password);<br /> $this->Email->to = $user['User']['email'];<br /> $this->Email->bcc = array('Your-Domain Accounts <accounts@your-domain.com>');<br /> $this->Email->subject = 'Password Change Request';<br /> $this->Email->from = 'noreply@your-domain.com';<br /> $this->Email->template = 'users_'.$this->action;<br /> $this->Email->sendAs = 'both'; // $this->Email->sendAs = 'both'; // you probably want to use both :) <br /> $this->Cookie->write('Referer', $this->referer(), true, '+2 weeks');<br /> $this->Session->setFlash('A new password has been sent to your supplied email address.');<br /> return $this->Email->send();<br />}
Done. Set the flash to inform the user of a sent out password. And a redirect back where they came from.
If you have another way to handle forgotten passwords in your sites, I would love to hear what you use, plugins or helpers to handle this kind of forgetfulness. Hit me up in the comments below.
You could eliminate a step:
1. Click “I forgot my password”
2. Enter your username and a new password
3. Confirm new password via e-mail
This way you don’t have to login with a temporary password and then change it again.
I guess a problem would be if someone clicks “confirm” but didn’t request the new password himself, the other would have access to his account. You’re probably better off protecting people from their own stupidity.
Could do that. Most of the time though I use the email as the username. If that is the case all you need do is aquire someones username, and change their password.
The email does provide that sense of security.
Unless, on a second read, you confirm the new password in an email?
Nice solution James, simple and elegant.
ElbertF’s idea is good but the email would need to stress the user NOT to click the link unless they requested a new password.
it’s a good post but there is a chance of flooding/security hole. Let somehow anybody knew others email address, he can reset others password by submitting forgot password stuff. So password should be rest upon confirmation from email address. i think so!
what if there’s no edit function? what if the password is hash?
Actually it is because the passwords are hashed that we need the edit function. It is not secure to store un-hashed passwords.
Nice trick dude. it helps me alot while creating forgot password page in my project. thanks for sharing it here.
There’s a way to reset password by sending a ticket link rather than a new password, that way the email is confirmed, and the password is only changed once the user has recieved the email.
http://edwardawebb.com/programming/php-programming/cakephp/reset-lost-passwords-cakephp
btw your code is all showing up on one line.