A simple authentication system with CakePHP 1.2 and Auth Component
I’ve been learning the CakePHP framework recently, and came to need a simple user login system.
Judging by the documentation out there, ACLs are the way to do it. However after spending an hour trying to figure out all the contradicting articles out there I gave up. ACLs are very precise, all I need is a simple “Sean is logged in” type of thing.
More reading on the Bakery pointed me to the Auth component, which does exactly what I need. Again though, I found incomplete documentation, which combined with reading some of the code and trial and error, I figured it out. What I ended up with was a system that:
- By default requires users to log in with a username (email) and password
- Guests trying to access a protected resource get redirected to the login screen
- Controllers can determine which methods need protection and which don’t
- Supports basic groups – registered users are “users”, admins are “admins”. The controller figures out the rest based on that string
- It’s easily understood, and doesn’t require a lot of code in each controller
So to start I need a user model:
CREATE TABLE `users` (
`id` int(11) NOT NULL auto_increment,
`email` varchar(255) NOT NULL,
`password` char(32) NOT NULL,
`role` varchar(20) NOT NULL default 'user',
`created` datetime default NULL,
`modified` datetime default NULL,
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1;
The corresponding model code (user.php) is:
class User extends AppModel {
var $name = 'User';
var $validate = array(
'email' => VALID_NOT_EMPTY,
'password' => VALID_NOT_EMPTY
);
function beforeSave() {
if ($this->data['User']['password']) {
$this->data['User']['password'] = md5($this->data['User']['password']);
}
return true;
}
}
As a password is written into the database, it is automatically md5′ed.
Because I want authentication on every page (with exceptions… hang in there) it’s done at the cake/app_controller.php level in a beforeFilter hook:
class AppController extends Controller {
var $components = array("Auth");
function beforeFilter() {
// Handle the user auth filter
// This, along with no salt in the config file allows for straight
// md5 passwords to be used in the user model
Security::setHash("md5");
$this->Auth->fields = array('username' => 'email', 'password' => 'password');
$this->Auth->loginAction = array('controller' => 'users', 'action' => 'login');
$this->Auth->loginRedirect = array('controller' => 'users', 'action' => 'myprofile');
$this->Auth->logoutRedirect = '/';
$this->Auth->loginError = 'Invalid e-mail / password combination. Please try again';
$this->Auth->authorize = 'controller';
}
All the $this->Auth lines fill in the various behaviours, such as what the login page is. Setting “authorize” to “controller” means each controller must have an isAuthorized() function that returns true or false if the already authenticated user is authorized to do the action. The key was setting the hash to MD5, because the default is SHA1 and that wasn’t working with my model I made earlier. You also must edit your config file to remove the salt. This behaviour may be recent though, I see some reports that the Auth component uses plaintext passwords which is untrue in HEAD.
With this in place, all pages will require authentication. To fix that, in the controllers you want to be open, add a beforeFilter:
function beforeFilter() {
$this->Auth->allow("*");
parent::beforeFilter();
}
This will allow all actions in the controller to pass without authentication. allow() seems to take a list of actions that don’t need authentication, * means all. If only a few actions needed authentication, I’d do $this->Auth->allow(“view”, “foo”) to allow the view and foo actions to be open.
If you need to see the user that is logged in, use $this->Auth->user(), which returns the model. From there I can get the role/group, or whatever else I put in there. It doesn’t seem you can set() variables for the view in the beforeFilter, so if you want the view to have part of the User model you should set() it elsewhere.
For my login function, I stole it directly from this tutorial. (Actually most of what I did was based on that tutorial, my contribution is really the explanation of the MD5 stuff and the allow() action (the latter which I now see is in his tutorial, just buried down in another section))
if ($this->Auth->user()) {
if (!empty($this->data)) {
if (empty($this->data['User']['remember_me'])) {
$this->Cookie->del('User');
} else {
$cookie = array();
$cookie['email'] = $this->data['User']['email'];
$cookie['token'] = $this->data['User']['password'];
$this->Cookie->write('User', $cookie, true, '+2 weeks');
}
unset($this->data['User']['remember_me']);
}
$this->redirect($this->Auth->redirect());
}
The rest of the code is fairly simple, a register action to set up an account, and a logout function to call $this->Auth->logout.

Muchas Gracias!!
Me sirvio mucho lo que escribiste.
Estaba tratando de entender como implementar el componente Auth y … me has ayudado un monton.
Saludos.
P/D: disculpame pero … se leer ingles pero no escribir
November 9th, 2007 at 6:37 amDid you get your cookie stuff working?
January 4th, 2008 at 2:53 pmGood article. To set() the current user, you can do that in beforeRender() as opposed to beforeFilter() like so:
beforeRender(){
$this->set(‘currentUser’, $this->Auth->user());
}
beforeRender is called after everything is done, just before the view is rendered.
February 21st, 2008 at 8:50 pmHello,
You said: You also must edit your config file to remove the salt.
I commented the following line in config.php
//Configure::write(‘Security.salt’, ‘DYhG93b0qyifIxfs2guVoUubWwvniR2G0FgaC9mi’);
I got the following error:
Division by zero [CORE\cake\libs\security.php, line 179]
Any Idea?
February 25th, 2008 at 5:08 amI write as you:
June 11th, 2008 at 12:11 amSecurity::setHash(“md5″);
but I got the following error:
Invalid Login.
this means the password was wrong,
can you tell me the reason and contact me with email
my email:mnbghj929.student@sina.com
Thanks!
my cakephp version:1.2…rc
I come from china.Welcome you !
@cake4arab: Set the salt to ”, don’t comment out the line.
@gerroy: Is the password in the database hashed with md5?
June 13th, 2008 at 8:28 amThat should be two single quotes, not a double quote.
June 13th, 2008 at 8:28 amHow can i access auth variable from layout+view+element, i cant figure it out
January 31st, 2009 at 4:31 amFYI: in the last block of code, it says $this->data['User']['pasword'];
February 5th, 2009 at 2:04 pmThere is an ’s’ missing in ‘Password’.
Nice article. Thanks.
February 15th, 2009 at 12:06 pmI think the reason why you had to remove the salt value was because you were using the php md5 function (which doesn’t add any salt value to your password) when you may have wanted to do something like this instead:
function beforeSave() {
December 1st, 2009 at 11:01 pmif ($this->data['User']['password']) {
$this->data['User']['password'] = $this->Auth->password($this->data['User']['password']);
}
return true;
}