Seeing that my article about the remember me cookie is the most popular on my site, I've decided to pack it all in a nice component.
Basically, take the code from this page (or get the whole file here) and put it here:
/app/controllers/components/remember_me.php
The code (badly formatted in an attempt to make it less scrollable):
class RememberMeComponent extends Object { var $components = array('Auth', 'Cookie'); var $controller = null; /** * Cookie retention period. * * @var string */ var $period = '+2 weeks'; /** * The model used to validate a user from the cookie. * * @var string */ var $userModel = array( 'name' => 'User', 'fields' => array( 'username' => 'username', 'password' => 'password' ) ); /** * Name of the cookie and its fields. * * @var string */ var $userCookie = array( 'name' => 'User', 'fields' => array( 'username' => 'username', 'token' => 'token' ) ); function startup(&$controller) { $this->controller =& $controller; } function _getModel($name = null) { $model = null; if (!$name) { $name = $this->userModel['name']; } $model = ClassRegistry::init($name); if (empty($model)) { trigger_error(__('RememberMe::getModel() - Model is not set or could not be found', true), E_USER_WARNING); return null; } return $model; } function remember($username, $token) { $cookie = array(); $cookie[$this->userCookie['fields']['username']] = $username; $cookie[$this->userCookie['fields']['token']] = $token; $this->Cookie->write( $this->userCookie['name'], $cookie, true, $this->period ); } function check() { $cookie = $this->Cookie->read($this->userCookie['name']); if (!is_array($cookie) || $this->Auth->user()) return; $model = $this->_getModel(); $user = $model->find( array( $this->userModel['fields']['username'] => $cookie[$this->userCookie['fields']['username']], $this->userModel['fields']['password'] => $cookie[$this->userCookie['fields']['token']] ), array(), null, -1 ); if ($user) { $model->data = $user; $model->id = $user[$this->userModel['name']][$model->primaryKey]; if ($this->Auth->login($model)) { $this->Cookie->write( $this->userCookie['name'], $cookie, true, $this->period ); } else { $this->delete(); } } } function delete() { $this->Cookie->del($this->userCookie['name']); } } ?>
The code can also be downloaded from here.
This code is slightly different from my previous version, as it does one more extra thing. When our user is logged in from a cookie, the cookie is written again and its retention period extended. By default, this cookie will expire after two weeks, but if our user visits the site often, this cookie will last forever.
Usage
To remember my user upon login, I now have this:
class UsersController extends AppController { var $name = 'Users'; var $uses = array('User'); function login() { if (!$this->Auth->user()) { if (!empty($this->data)) { if (empty($this->data['User']['remember_me'])) { $this->RememberMe->delete(); } else { $this->RememberMe->remember( $this->data['User']['username'], $this->data['User']['password'] ); } unset($this->data['User']['remember_me']); } } $this->redirect($this->Auth->redirect()); } function logout() { $this->RememberMe->delete(); $this->redirect($this->Auth->logout()); } }
And in my AppController, I have the following:
class AppController extends Controller { var $components = array('RememberMe'); function beforeFilter() { // component settings are customizable here, // much like the Auth component.. For example: // $this->RememberMe->period = '+2 months'; // snip... $this->RememberMe->check(); // snip.. } }
That's it! If you find it useful of have an improvement to suggest, please leave a note!
Happy baking!
Article comments — View · Add
I think something didn't work when I tried that at first, but that was my first contact with Cake, I might have done something terribly wrong... :-)
I'll try it and update the article if I succeed this time. [doh]
Thanks Baz ;-)
I don't worry too much about that. If someone has access to your cookies, I think they are the last thing you need to worry about.. :-)
This is not quite working for me atm. I've tracked down the problem and it's that by the time UsersController.login method is called, the data.User.Password is gone.
Not sure exactly where yet, but the Auth component is called BEFORE, does its magic, unsets the password and by the time you want to use the password value for the cookie, it's just blank.
I'm on Cake 1.2.0.7296 RC2, is this supposed to work there?
Thanks!
Juan