In the comments for my seemingly-popular post about using CakePHP's Auth component (available in CakePHP 1.2), people have been having some questions about how the password is hashed and questions about a user registration system. Of course, the snarky response is "go and read the source for Security::Hash() and create some of your own code", but it is easier to just give people some code so they stop asking.
I'm in the process of building out an admin area for my simulation baseball league web site, and I created a registration system. Here's a condensed version of it.
First, I have my User model
-
<?php
-
class User extends AppModel {
-
-
var $name = 'User';
-
var $useTable = 'users';
-
}
Next, I created my controller for my users and the registration action for it
-
class UsersController extends AppController {
-
var $name = 'Users';
-
-
function beforeFilter() {
-
$this->Auth->allow('register');
-
}
-
-
function register() {
-
if ($this->data['User']['password'] == $this->Auth->password($this->data['User']['password_confirm'])) {
-
$this->User->create();
-
$this->User->save($this->data);
-
}
-
}
-
}
-
}
So, let's dissect this controller:
- We're using the Auth component, set via "var $components = array('Auth')"
- We tell Auth to not ask for authentication when doing the 'register' action
- When we detect data coming into the 'register' action (usually via a POST), then check to see if the hashed password that Auth has created from the 'password' field in our form matches the hashed value of the 'confirm password' field from our form
- If all that is okay, we create and save our new user record
Yes, it really is that easy.
The form for this is very simple as well
Throw all that stuff together and you now have a very simple user registration system.
Tags: auth, CakePHP

Hy,
this is just what I need, a simple registration example. But I think that line 12. isn't right.
if ($this->data['User']['password']==$this->Auth->password($this->data['User']['password_confirm']))
how can you compare this two password values if the first value isn't a hash value and the second is?
@Davor
In this example, Tthe Auth component automatically hashes $this->data['User']['password'] for you, that's why it works. If I had changed the default password field to something else (some people use 'passwd' as the field name in their User model) then the Auth component would automatically hash $this->data['User']['passwd'] for you.
Hope that helps.
@Chris
It helps, thanks.
I have another question, about input validation. How would you validate if username is for example not less than 6 char and not more than 10 char ?
I'm a bit confused about AppModel's variable $validate...
@Davor
Check out the section on 'Data Validation' over at http://tempdocs.cakephp.org
In a related question to Davor's, how do you handle verifying the length of passwords when registering? Because the Auth component hashes the password, you can't then compare it with the password_confirm field?
@Stephen
It's quite easy to verify length under the system I proposed above. You can verify the length of password_confirm, and then do the comparison check in line 12 of my sample code. You do have to make an assumption on the length of the password because I guess there is an statistically improbable chance that two string of different lengths would be hashed the same.
Hey Chris,
Just a minor correction, sorry: you need the input field password to be array('type' => 'password') as the password_confirmation one on the form.
@Gustavo
Actually, you don't need to do that at all. The Form helper is smart enough to know that you want a 'password' field type when you create an input field called 'password'. The code up above is what I'm actually using in an application and the field does turn into a password field.
Hi Chris,
Just wonder if submitting empty passwords will work. I had this problem but quite a while ago since the Auth compoment's hashPasswords method would hash an empty field anyway (and a model validation for checking empty will never be hit). Maybe the component has been modified since.
Cheers
Hi,
I've been puzzling over user registration for some time, although using my own Auth component. The problem I have, and one that it seems isn't often addressed, is outputting validation errors to the user.
For example if the two passwords do not match, or invalid characters in the username. I know this should be taken care of by core validation but I cannot find an example anywhere.
@Matt
I have used model verification to handle this sort of thing, the key being that you need to have that second verification field for the passwords. I'll do up a blog post showing what I did.
I do not see beforeFilter() in the api. Where is that defined?
nevermind. I was looking at AppModel not AppController. forgive me.
Hi,
I am trying to get auth up and running as a first step...
when i go to example.com/foo it redirects me to /users/login/ i enter my info, and i go to /foo
in my fooController::index() i have $this->set('email', $this->Auth->user('email'));
in my view i simply echo $email;
instead of seeing my email i get a calling function on non-object crap... i followed the tempdoc.cakephp.org example...any idea what i could be doing wrong?
Ok...so it appears that despite Auth kinda working, you have to ensure that var $components = array('Auth'); and not var $components = array('auth');
How does Auth know that register belongs to it (to hash the password)? Because, it's not hashing it for me.
I am using a table that is not called "users". That's not supposed to be a problem in theory - in practice, is anyone doing this?
@Jen
If you tell the Auth component the name of your table that you're using, then it should automatically hash the password field for you.
Thanks, I had a dumb typo. Working now.
Great tutorials, thanks!
How would you have the register() method automatically log the user in once the data has been validated and saved? I'm trying to avoid having the user immediately need to login after a successful registration.
Great tutorials...thanks!
@Ryan
I believe you can manually log someone in by placing their login credentials into an array and then passing it to the login method of the component. But you have to have their non-hashed password stored somewhere in order to make it happen
$password = $this->Auth->password($nonHashedPassword);
$data = array('username' => 'foo', 'password' => $password);
$this->Auth->login($data);
Thanks for the great tutorial
. I followed all your instruction and everything went fine and dandy except one thing. I ran into this problem: when the registration process fails by any reason (passwords do not match, repeated login, etc), the form reloads itself with the error code, but for some reason, my password field isn't being empty but filled with the hashed password that generated from the system. I tried a couple option attribute like array('empty'=>true) or change from $form->input('password') to $form->password(...) but none works for me.
Any help or suggestion will be greatly appreciated!
Thanks,
use echo $form->input('new_password', array('value' => ''));
AS another user mentioned the auth component will hash even blank passwords which is a basic validation rule, this problem could be addressed using other JS validation (you should have double validation, client and server) .
Now to validate on the server side dont use the standard password field name and then hash the password yourself on beforesave() , make sure u use the salt. sorry cant go into detail i have no time ! good luck. ps: consider another mature framework
Nice articl, but what if the passwords are not equal? How will I display an error message? Should I invalidate that field in the else statement or display and error with setFlash? What do you recommend?
Is this example safe against hacks? I mean if a user adds a hidden field named 'id' on his browser, wouldn't your example edit the existing user? I think that cake will search for the user with the given id and change it's password instead of creating a new one.
@elvman
That example is just that: a simple example. If you read up on the using the Security component, I think you'll find info in there on how to prevent the exact thing you're talking about. This is, of course, without me going and looking for myself.
Shouldn't the form fields in the register.ctp file be in the form:
$form->input('User/username');
$form->input('User/password');
$form->input('User/password_confirm'...)
Otherwise the $this->data['User'][field_name] references in the controller won't be correct .. ?
Follow-up question.
My registration form includes 'User' information as well as 'Address' information.
These two database tables are associated. (User hasOne Address).
How do I save BOTH the User object AND the Address object when I click the submit button?
In other words, when saving the User, how do I also save the associated Address? Help me setup the form.
Thanks,
Dave
[...] - Simple User Registration in CakePHP 1.2 http://www.webdevelopment2.com - CakePHP Auth Component For Dummies Tutorial http://www.webdevelopment2.com - [...]
Simple and Straight forward tutorial . thanks nice write up for beginners though ..
As a Cake noob myself, I want it to use $validate in the model for the confirm password. However, the validation is only called in the model->save() so you need to call model->validates() explicitly or else {} in the controller and $this-->flash('Mismatch');
[...] http://www.littlehart.net/atthekeyboard/2008/01/08/simple-user-registration-in-cakephp/ [...]
Great tutorials-----thanks.
send this type of articles regularly for beginners .
thanks again
Using all the supplied code straight off up there, gave me this error for some odd reason:
Notice (8): Undefined property: UsersController::$User [APP\controllers\users_controller.php, line 33]
Code
if ($this->data['User']['password'] == $this->Auth->password($this->data['User']['password_confirm']))
{
$this->User->create();
UsersController::register() - APP\controllers\users_controller.php, line 33
Object::dispatchMethod() - CORE\cake\libs\object.php, line 115
Dispatcher::_invoke() - CORE\cake\dispatcher.php, line 227
Dispatcher::dispatch() - CORE\cake\dispatcher.php, line 194
[main] - APP\webroot\index.php, line 88
And I personally got no idea what's wrong, kinda new to the whole concept of Cakephp.