CakePHP 1.2.* Auth Component Tutorial
There are a lot of tutorials out there on how to use the Auth component in CakePHP but everything that I’ve found so far has been lacking for my need – so I wrote my own. Recently I needed a way to set up a simple authentication mechanism I could use for customer websites in order for them to log in and manage their content. Since I use CakePHP for everything these days one of the simplest solutions was to utilize the built in authentication component which can be a little tricky to set up since the documentation is a little vague and scattered over the Internet.
All of this code is provided in a zip file at the bottom of this post. Also, feel free to leave any feedback if you have comments or suggestions.
Database
The first thing you will want to do is create a user table in your site database:
/app/config/sql/users.sql
`id` int(11) unsigned NOT NULL auto_increment,
`username` varchar(20) NOT NULL default '',
`password` varchar(40) NOT NULL default '',
`name` varchar(40) NOT NULL default '',
`email` varchar(60) NOT NULL default '',
`created` datetime default NULL,
`updated` datetime default NULL,
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=1;
Your table doesn’t have to be exactly like this so feel free to adjust it to your own needs. However later on I will include CRUD pages for the users and you may need to adjust them to suit your changes.
User Model
Now that you have your table set up lets create the user model.
/app/models/user.php
|
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 |
<?php
class User extends AppModel { var $name = 'User'; var $useTable = 'users'; var $validate = array( 'username' => array( 'empty' => array( 'rule' => 'notEmpty', 'required' => true, 'allowEmpty' => false, 'message' => 'Please enter a username' ), 'length' => array( 'rule' => array('minLength', 4), 'required' => true, 'allowEmpty' => true, 'message' => 'Usernames must be at lest 4 characters long' ), 'alphanum' => array( 'rule' => 'alphaNumeric', 'required' => true, 'allowEmpty' => true, 'message' => 'Only letters and numbers are allowed in usernames' ), 'unique' => array( 'rule' => 'isUnique', 'required' => true, 'allowEmpty' => true, 'message' => 'That username is already in use by another user' ) ), 'clear_password' => array( 'empty' => array( 'rule' => 'notEmpty', 'required' => true, 'allowEmpty' => false, 'on' => 'create', 'message' => 'Please enter a password' ), 'length' => array( 'rule' => array('minLength', 6), 'required' => true, 'allowEmpty' => true, 'message' => 'Passwords must be at lease 6 characters long' ) ), 'confirm_password' => array( 'empty' => array( 'rule' => 'notEmpty', 'required' => true, 'allowEmpty' => false, 'on' => 'create', 'message' => 'Please confirm the password' ), 'emptyUpdate' => array( 'rule' => 'emptyUpdate', 'required' => true, 'on' => 'update', 'message' => 'Please confirm the password' ), 'match' => array( 'rule' => 'matchPasswords', 'required' => true, 'allowEmpty' => true, 'message' => 'The passwords you entered do not match' ) ), 'name' => array( 'rule' => 'notEmpty', 'required' => true, 'allowEmpty' => false, 'message' => 'Please enter a name' ), 'email' => array( 'empty' => array( 'rule' => 'notEmpty', 'required' => true, 'allowEmpty' => false, 'message' => 'Please enter an email address' ), 'email' => array( 'rule' => 'email', 'required' => true, 'allowEmpty' => true, 'message' => 'Please enter a valid email address' ), 'unique' => array( 'rule' => 'isUnique', 'required' => true, 'allowEmpty' => true, 'message' => 'That email address is already in use by another user' ) ) ); function emptyUpdate() { if (!empty($this->data['User']['clear_password']) && empty($this->data['User']['confirm_password'])) { return false; } else { return true; } } function matchPasswords() { if ($this->data['User']['clear_password'] != $this->data['User']['confirm_password']) { return false; } else { return true; } } } ?> |
I went ahead and included all the validation that I use as well so again feel free to adjust as necessary.
Users Controller
And then for the Users Controller…
/app/controllers/users_controller.php
|
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 |
<?php
class UsersController extends AppController { var $name = 'Users'; var $uses = array('User'); function beforeFilter() { parent::beforeFilter(); } function index() { $users = $this->User->find('all'); if (empty($users)) { $this->Session->setFlash('There are no users defined', 'default', array('class'=>'bad')); } else { $this->set('users', $users); } } function view($id) { $user = $this->User->findById($id); if (!empty($user)) { $this->set('user', $user); } else { $this->Session->setFlash('Invalid User ID', 'default', array('class'=>'bad')); $this->redirect('index'); } } function add() { if (!empty($this->data)) { $this->User->set($this->data); if ($this->User->validates()) { $this->data['User']['password'] = $this->data['User']['clear_password']; $this->User->save($this->Auth->hashPasswords($this->data), false); $this->Session->setFlash($this->data['User']['name'].' Added', 'default', array('class'=>'good')); $this->redirect('index'); } else { $this->Session->setFlash('Please correct the errors below', 'default', array('class'=>'bad')); } } } function edit($id = null) { if (!empty($this->data)) { foreach ($this->data['User'] as $field => $data) { if (!in_array($field, array('clear_password', 'confirm_password'))) { $fields[] = $field; } } if (!empty($this->data['User']['clear_password']) || !empty($this->data['User']['confirm_password'])) { $fields[] = 'password'; $fields[] = 'clear_password'; $fields[] = 'confirm_password'; } $this->User->set($this->data); if ($this->User->validates()) { if (!empty($this->data['User']['clear_password'])) { $this->data['User']['password'] = $this->data['User']['confirm_password']; } $this->User->save($this->Auth->hashPasswords($this->data), false, $fields); $this->Session->setFlash($this->data['User']['name'].' Updated', 'default', array('class'=>'good')); $this->redirect('index'); } } else { $user = $this->User->findById($id); if (empty($user)) { $this->Session->setFlash('Invalid User ID', 'default', array('class'=>'bad')); $this->redirect('index'); } else { unset($user['User']['password']); $this->data = $user; } } } function delete($id) { $user = $this->User->findById($id); if (empty($user)) { $this->Session->setFlash('Invalid User ID', 'default', array('class'=>'bad')); } else { if ($user['User']['id'] == $this->Session->read('Auth.User.id')) { $this->Session->setFlash('Sorry, you can not delete yourself', 'default', array('class'=>'bad')); } else { if ($this->User->del($id)) { $this->Session->setFlash($user['User']['name'].' Deleted', 'default', array('class'=>'good')); } else { $this->Session->setFlash('Failed to delete '.$user['User']['name'], 'default', array('class'=>'bad')); } } } $this->redirect('index'); } function login() { // Auth Magic } function logout() { $this->Session->del('Auth.User'); $this->Session->setFlash('Your are now logged out', 'default', array('class'=>'bad')); $this->redirect('login'); } } ?> |
Before Filter
I have found that it is a good habit to always inherit your app controller’s before filter. You will not want to forget this if you customize any of the Auth component variables. Otherwise they will not be set as you expect when you declare a beforeFilter method in any other controller. You may have noticed the array of methods I passed to Auth component. You will need to uncomment that line in order to add users after enabling the Auth component in your app controller or you will be locked out of your site. You will also want to add similar before filters in all your other controllers to control access accordingly. Please see the documentation for the allow method for more information.
Password Hash Issue
One of the things I find irritating about the Auth component is how it uses the hash in the config file to encrypt the password by default instead of using something easy like md5. I’m sure they have their reasons and supposedly you can change it by setting Security::setHash(‘md5′); somewhere but I wasn’t able to get that working right. So I just figured out how to work with it as is.
If you take a look at the add function in the users controller you will see how I managed it. The first problem was that Auth encrypts the password field immediately. So if you had any errors in the registration the password that is placed back in the form field is encrypted and will no longer match the confirm password field. I changed the name of the password field to clear_password and then did my validation against that. After it passes validation the password is set and encrypted in the save.
Only change the password if one is entered problem
Now if you look at the edit function you will notice another problem. Usually in order to avoid creating a separate change password function I like to set up the password fields in the edit user page. If the password and confirm password are not entered then the password will not be changed. This creates a problem with cake because it likes to validate fields for us and the Auth component will even take a blank value and produce a nice 40 character hash string. So the craziness that is going on there is just a way around that issue using the additional fields attribute for the save method.
Other Controllers
Now don’t forget to open up your other controllers and add a before method with an exception for your public pages:
parent::beforeFilter();
$this->Auth->allow('index');
}
You could also allow(‘*’) in your app_controller and then specify which pages to deny, whichever way is easiest for you.
If you have any plugins you will also need to add before filters to the plugin app controller and all of the plugin controllers. If all the methods in a controller require authentication you can feel free to leave out the Auth->allow. Also never add an exception for login and logout. I have seen several people doing this and it is not necessary and could possibly break the auth component.
User Views
There is not a whole lot to explain here. It is just a the views for the users controller. Feel free to use them or ignore them.
/app/views/users/add.ctp
|
1
2 3 4 5 6 7 8 9 10 11 |
<h2>Add User</h2>
<?php echo $form->create('User', array('url' => '/users/add')); echo $form->input('username', array('size' => '20')); echo $form->input('clear_password', array('type' => 'password', 'size'=>'20')); echo $form->input('confirm_password', array('type'=> 'password', 'size' => '20')); echo $form->input('name', array('size' => '35')); echo $form->input('email',array('label' => 'Email Address', 'size' => '40')); echo '<div><input type="submit" value="Submit" /> or '.$html->link('Cancel', array('action' => 'index')).'</div>'; echo $form->end(); ?> |
/app/views/users/edit.ctp
|
1
2 3 4 5 6 7 8 9 10 11 12 13 |
<h2>Edit User</h2>
<?php echo $form->create('User', array('url' => '/users/edit')); echo $form->input('username', array('size' => '20')); echo 'Leave the password fields blank if you do not wish to change this users password'; echo $form->input('clear_password', array('type' => 'password', 'size'=>'20')); echo $form->input('confirm_password', array('type'=>'password', 'size' => '20')); echo $form->input('name', array('size' => '35')); echo $form->input('email',array('label' => 'Email Address', 'size' => '40')); echo $form->hidden('id'); echo '<div><input type="submit" value="Submit" /> or '.$html->link('Cancel', array('action' => 'index')).'</div>'; echo $form->end(); ?> |
/app/views/users/index.ctp
|
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
<h2>Users</h2>
<div> <?php echo $html->link('Add User', array('action' => 'add')); ?> </div> <hr /> <table width="100%"> <tbody> <tr> <th>ID</th> <th>Name</th> <th>Email</th> <th></th> </tr> <?php if (!empty($users)) { foreach ($users as $i) { echo '<tr>'; echo ' <td>'.$i['User']['id'].'</td>'; echo ' <td>'.$i['User']['name'].'</td>'; echo ' <td><a href="mailto: '.$i['User']['email'].'">'.$i['User']['email'].'</a></td>'; echo ' <td class="actions">'; echo $html->link('View', array('action' => 'view', $i['User']['id'])).' | '; echo $html->link('Edit', array('action' => 'edit', $i['User']['id'])).' | '; echo $html->link('Delete', array('action' => 'delete', $i['User']['id']), null, 'Are you sure you want to delete this user?'); echo ' </td>'; echo '</tr>'; } } ?> </tbody> </table> |
/app/views/users/login.ctp
|
1
2 3 4 5 6 7 |
<h2>Login</h2>
<?php echo $form->create('User', array('url' => '/users/login')); echo $form->input('username', array('size' => '20')); echo $form->input('password', array('size' => '20')); echo $form->end('Login'); ?> |
/app/views/users/view.ctp
|
1
2 3 4 5 6 7 8 9 10 11 |
<h2><?php echo $user['User']['name']; ?></h2>
<div> <?php echo $html->link('Back to Users', array('action' => 'index')).' | '; echo $html->link('Edit', array('action' => 'edit', $user['User']['id'])).' | '; echo $html->link('Delete', array('action' => 'delete', $user['User']['id']), null, 'Are you sure you want to delete this user?'); ?> </div> <hr /> <p>Username: <?php echo $user['User']['username']; ?></p> <p>Email Address: <?php echo '<a href="mailto: '.$user['User']['email'].'">'.$user['User']['email'].'</a>'; ?> |
App Controller
Now that everything is set up let’s enable the auth component in the app controller (If you do not have one you may need to create it).
/app/app_controller.php
|
1
2 3 4 5 6 7 8 9 10 11 |
<?php
class AppController extends Controller { var $components = array('Auth'); function beforeFilter() { $this->Auth->loginAction = array('controller' => 'users', 'action' => 'login'); $this->Auth->logoutRedirect = array('controller' => 'users', 'action' => 'login'); $this->Auth->loginRedirect = array('controller' => 'users', 'action' => 'index'); } } ?> |
Login Action
The login action used here is actually set by default. You will need to change this if you have a different name for you users controller or login action.
Logout Redirect
The logout redirect is where users will be redirected after logging out. This is also set to users->login by default.
Login Redirect
Login redirect is actually a fall back option. Do not expect this to always redirect your users to the page specified by this option after logging in. The auth component stores the last visited page in the session and will redirect a successful login there unless autoRedirect is set to false in which case you will need to write a custom login function and handle redirection there. Or if a user has no previous session information (for example if they linked directly to the login page) in which case the auth component will use the login redirect method. This behavior is not very well documented on the Cake website. I actually found the answer in a closed bug report.
Because of the default options though you should be able to leave that stuff out and still be okay.
All Done!
Now you may visit /users/add and create a user account so you can log in and manage your site. DO NOT forget to remove the allow in your users controller for all the different pages you do not want to be public.













Thanks for the very well done tutorial. I have been hacking through a dozen different CakePHP auth tutorials and yours was the best I found. I did have to make some tweaks since my usage is a lot different. Great job though.
Thanks Micah, I’m glad it helped you out
Happy New Year!
Joseph, first I must say this is the most clear and defined explanation of user authentication and validation for Cake that I’ve seen so far. I’m not sure what is happening with my particular problem, or even that anyone can help; I copied your code nearly verbatim and still cannot even get the simplest validation rule to process. I’ve upgraded to the final release and I’m sure that it is something completely simple that I’m overlooking though after hours of frustration I thought it would be a good idea to throw it out there. I hope your year is bliss!
Thanks rcharm! I’m sorry to hear your having trouble. If you want you could email me the code from your model and I will see if I could be of any help. jbcrawford at gmail dot com. Hope you have a great new year as well
Joseph, thanks for the tip about inheriting the app controller’s beforeFilter(). I couldn’t figure out why Auth -> loginRedirect wasn’t doing its job, but I think you and Google saved the day.
hi,
I saw ur article its too nice.I am having the trouble when i use the user name as a session.how can i receive the user name value in the index page.
@vijay
Hey vijay,
Thanks for the comment!
If you read the session Auth variable into your view you should be able to do it with something like this…
echo $info['User']['username'];
Hope that helps
Hi Joseph,
Thanks for your reply man.Its working yar.Really its nice coding.Shall you tell me how to edit only user’s log in name and password.
Hey Josep,
read(‘Auth’);
$id= $info['User']['id'];
?>
I used this code to receive the id value for logged in person and now i want to edit that person user name and password.how can i put this value in below mension edit link.
link(‘EditProfile’, array(‘action’ => ‘edit/$id’));
?>
Presently i am using this way.
<a href=”edit/”>EditProfile
I know it is not a good method in php.Is there any good coding for editing the profile?
Thanks
@vijay
Using the html helper you could create a link to the edit user page like this:
If you have this link in your layout you will want to specify admin, plugin and controller so the link will work while you are viewing pages created by other controllers. Otherwise if you just specified array(‘admin’ => ‘edit’, $info['User']['id']) and you pulled up /foo/index you would get an error when you click the link because it would take you to /foo/edit/$id.
Great Job Joseph!!!
This is the only place that I found a complete solution that works! One of my problems was the user edit form…now the user password just changes if the clear_password and confirm_password are filled.
And the other problem was the add user form too…now, when i got errors, the password fields remain intact.
Congratulations and thank you very much!
@Fernando MSWI
Thanks for the great comment Fernando. Glad it worked for you!
Really Thanks to you Joseph!!! Its working.
Now am looking for file uploading using cake php is there any coding for file upload and view?
Hi, thanks for these useful informations.
I’m wondering, if there is a way for adding a function just after the login. For example, I would likfe to update a ‘last_visit’ data just after the user logged in succcesfully. Do you have any idea how I can have this with the Auth Magic in the login function? DO I have to rewrite manually the login function?
Thank you
Check out the section on file fields in the manual, it should be very helpful. Just don’t forget to change your enctype to multipart/form-data.
I am afraid you would have to write a custom login function for that. I have seen an example of one somewhere before. Possibly on Mark Story’s website.
Thankyou for the very much for your easy to understand Auth Component Tutorial. I have been tring somany days to solve this problem.At last it was sucessful by your codes
Well done!!!
A great tutorial..
Regards
Ajay1kumar1
I’m about to cry I’m so happy. You proved that AuthComponent actually DOES WORK! Now to extend it for LDAP …
Haha! Good luck with LDAP, it’s not fun
Well, luckily I already had a working LDAP Class that I wrote for PHP, and I’d found some other scripts talking about extending AuthComponent for LDAP, so between that and my LDAP class which I’m using as a vendor to keep the LDAP logic out of the model, everything is working! But you’re right … connecting to LDAP has never been fun. Getting PHP to talk to the LDAP server securely was an even bigger challenge.
I had to set up authentication for an intranet off active directory back in the cake 1.1 days. I didn’t even attempt to do it over ssl. Glad you got it working though, have a great weekend!
You mentioned an issue with the password hash. In another app I was working on, I was able to use a sha1 hash by:
1) Putting this in my app controller:
Security::setHash(’sha1′);
2) Commenting out the Configure::write(‘Security.salt’ etc… line in core.php
Was just messing around and it worked just fine, but not sure if commenting out that salt line could be unwise for some reason.
I guess as long as it doesn’t break anything it should be okay
I had tried to set Security::setHash(’sha1′); in the app controller but it never seems to grab, maybe commenting out the salt is the trick…or it was just a problem with the beta version I was using at the time.
Thanks for the comment though, well worth keeping in mind
Hi Joseph ,
Thanks for the very well done tutorial.
Is there any possibility to display 3 select boxes using 3 different tables datas in one page.I need ur help.
In the paragraph entitled “Before Filter” you wrote:
“You may have noticed the array of methods I passed to Auth component. You will need to uncomment that line in order to add users after enabling the Auth component in your app controller or you will be locked out of your site.”
I’m not finding anywhere in the article or source code where you passed an array of methods to auth. In the “Other Controllers” paragraph you pass ‘index’ to the auth component in the beforeFilter() callback. I’m a little confused about your meaning.
I’m trying to make this work with admin routing so it’s a little different than your example.
Great tutorial though. Thanks!
I’m sorry I must have deleted that from the example code. The array I mentioned was to allow access to the users pages in order to add your first user. To do so you would need to add $this->Auth->allow(‘*’); to the end of your beforeFilter. After you create your first account remove that line and then log in. Nothing should change much if you are using admin routing. Update the controller function names as well as the view file names. Be sure and update the url in the user add/edit views.
And you may also need to modify the Auth stuff in the app controller. For example: $this->Auth->loginAction = array(‘controller’ => ‘users’, ‘action’ => ‘login’); would become $this->Auth->loginAction = array(‘admin’ => false, ‘controller’ => ‘users’, ‘action’ => ‘login’); Update logoutRedirect similarly. And the loginRedirect would be $this->Auth->loginRedirect = array(‘admin’ => true, ‘controller’ => ‘users’, ‘action’ => ‘index’);
Hope that helps, let me know…
Wonderful Tutorial
Thanks
I’ve posted this to two other old articles and haven’t heard back – glad to see that this is very recent
. I am struggling with having the authComponent use email instead of username for login. Cake Version 1.2
This is what I have in app_controller:
var $components = array(’Auth’);
function beforeFilter() {
$this->Auth->fields = array(
‘username’ => ‘email’,
‘password’ => ‘password’
);
}
This is what I have in login.ctp:
echo $form->create(’User’, array(’action’ => ‘login’));
echo $form->input(’email’);
echo $form->input(’password’);
echo $form->end(’Login’);
I have verified that the registration is working – db is storing users perfectly w/ hashed password. Even after changing the fields in the app_controller before filter, I am getting “Login failed. Invalid username or password.” as the auth flash message.
Some advice / code related to using email in place of username for the authComponent…? Thanks in advance!
Hello Bryan,
What about just using an email address in the username field? I know it kind of throws semantics out the window but if it works?
It sounds like your situation should work though. They even use the ‘username’ => ‘email’ as an example of Auth->fields in the book. Are you executing the app controllers before filter in your users controller?, like…
function beforeFilter() {
parent::beforeFilter();
}
Hi Joseph, thanks for the great tutorial! I am a newbie with cakephp, and this has really helped me understand the Auth component better.
I had a quick question (which I hope is not too silly). I am currently building a site with two types of users, teachers and students. Each type of user needs to be authenticated and should be stopped from accessing actions meant for the other kind of user. I am not sure how to handle this situation with cakephp, specifically:
- Is it possible to accomplish this with just the Auth component or is the ACL component needed? Can you ask the Auth component to look at different models depending on the controller?
- Should I have just one User model with a “type of user” field or is a two model approach (a Student model and a Teacher model) better?
Im just looking for advice on what approach to take. Thanks very much in advance!
Hello Abhishek,
Yes it is possible with the Auth component and only one User model/table. Assuming your groups would not change very often you could add a group field to your users table that has like 3 possible values (‘Admin’, ‘Student’, ‘Teacher’), I added the Admin that would be for like your account…you don’t have to do that. You could also create another table for groups, a Group model, group_id to your users table, and a $belongsTo = array(‘Group’) in your User model.
However you choose to do that part of it the next part is pretty much the same.
Add this stuff to your app_controller.php if not there:
class AppController extends Controller {
var $components = array('Auth');
var $user;
function beforeFilter() {
$this->Auth->loginAction = array('controller' => 'users', 'action' => 'login');
$this->Auth->logoutRedirect = array('controller' => 'users', 'action' => 'login');
$this->Auth->loginRedirect = array('controller' => 'users', 'action' => 'index');
$this->Auth->authorize = 'controller';
$this->user = $this->Session->read('Auth.User');
}
}
?>
And now in every controller in your application you will need an isAuthorized() method which allows you to do some access control.
class ExampleController extends AppController {
var $name = 'Example';
function beforeFilter() {
parent::beforeFilter();
}
function isAuthorized() {
switch($this->user['group']) {
case 'Teacher':
$permission = true;
break;
case 'Student':
switch($this->action) {
case 'index':
$permission = true;
break;
case 'add':
case 'edit':
case 'delete':
$permission = false;
break;
}
break;
case 'Admin':
$permission = true;
break;
default:
$permission = false;
break;
}
return $permission;
}
}
?>
If all of the methods in your application are pretty standard you could just place an isAuthorized method in your app_controller and cover everything. So that you don’t need one in every controller. Just depends on what you want to do.
Also you can do anything you want in the isAuthorized method to determine permissions as long as you return true or false in the end. You could also set up the Acl component but that may be a overkill.
Anyway, hope that helps…best of luck!
Oops! I completely overlooked the isAuthorized() method in the Auth component. That makes things very easy, thanks so much for the tip! Is it possible to attach a custom error message when isAuthorized() returns false? Either way, thanks for the help! Cheers from Berlin.
I like to use setFlash in the session component. I don’t even think you really have to return false. I’ve used redirect to send them to an access denied page before.
Your lucky to be in Berlin…that means you could easily go to Cakefest this year. I’m jealous, Germany gets all the good *fests, lol
Hi Joseph, I’m new to cake PHP and I wonder why when I try to go to http://localhost/users/add, I would always be redirected to http://localhost/users/login. I am not able to add new users. Anyone also please help?
@TJ
I missed setting the below at app_controller. With that changed, I am now able to access http://localhost/users/add. Great tutorial btw!
$this->Auth->allow(‘*’)
This is very good stuff. I especially appreciated the answer to the question from Abisheck on restricting access to actions based on a group_id that a user belongs to.
Now… with that approach a Student can only do actions applicable to a Student and not a Teacher. Great!
However, how do we extend this so that a Student can only do actions applicable to their own student number? Also, a Teacher should be able to do actions to their students, but not students of other teachers.
This extension will help me greatly as I am trying to build an application similar to this but with distributors, dealers, customers, and vehicles. The principles are the same for Teacher (aka Distributor) and Student (aka dealer).
Thanks in advance for your help!
@Frederick D.
Hello Frederick,
It sounds like you may need to use the ACL Component for your situation. Mark Story has a pretty good article that could help you. I have been planning a tutorial that would fit your need perfectly I think but I’ve just been so busy lately I haven’t had the time to sit down and do it. Feel free to email me though if you run into any problems. jbcrawford at gmail dot com. Also the #cakephp channel on IRC can be pretty helpful.
@Joseph
I think I just solved it using model relationships. Here’s what I’ve got for relationships:
Groups->hasManyUsers
Users->belongsToGroups, hasOneDistributor, hasOneDealer
Distributors->belongsToUsers, hasManyDealers
Dealers->belongsToUsers, belongsToDistributors
When creating a Distributor you select a User.Id for the Distributor row. When creating a Dealer you select a Distributor.Id and a User.Id for the Dealer row.
Now when a user logs in, and I have their User.Id, when they are in the group=Distributor, I can go grab the applicable Distributor(s) for their User.Id. That also automagically (depending on the setting for recursive) gets me the Dealers associated with the Distributor.
Using a “conditions” array I either load the User.Id value (for that distributor) or get all (if the user is Admin).
It is actually pretty cool. So far I have not had to use ACL. I think I can broadly allow/disallow CRUD actions based on the group for my application. For instance, a group=Distributor could use CRUD for their dealers, but no others.
I think I’m making progress… and in a forward direction! I will be extending the application for Service Advisors that belong to a Dealer and to Customers that will belong to a Dealer.
I’m impressed with the power of CakePHP to do this so well for me.
If you like we could perhaps collaborate on a tutorial in the future. I think it is awesome to be able to use the AuthComponent and model relationships instead of ACL.
function add() {
if (!empty($this->data)) {
$this->User->set($this->data);
if ($this->User->validates()) {
$this->data['User']['password'] = $this->Auth->password($this->data['User']['new_password']);
$this->User->save($this->data, false);
$this->Session->setFlash(__(‘The User has been saved’, true));
$this->redirect(array(‘action’ => ‘index’));
} else {
$this->Session->setFlash(__(‘The User could not be saved. Please, try again.’, true));
}
unset($this->data['User']['new_password']);
unset($this->data['User']['retype_password']);
}
}
function matchPasswords() {
return $this->data[$this->name]['new_password'] == $this->data[$this->name]['retype_password'];
}
What do you keep posting code for?
Thanks for the great tutorial, it make me understand better the Auth component. Maybe you should evidence the following points:
- the IsAuthorized method should be added at least in the app_controller.php
- the display action should be allowed in the app_controller.php otherwyse it’s impossible to serve static pages
- if the app has to show both auth and normal flash messages, in the login page the following code must be added
check(‘Message.flash’)) {
$session->flash();
}
if ($session->check(‘Message.auth’)) {
$session->flash(‘auth’);
}
Thanks again i was desparate to make the Auth component work.
?>
Hi Joseph!
Good Post!
Congratulations. but, im having a problem similar to that reviewed by Bryan.
I tried what you recommended, but not worked.
the code is here: http://groups.google.com/group/cake-php/browse_thread/thread/43b0196a16232e2b
you could give me a hand?
@Wladiston Paiva
Hi Wladiston, sorry it has taken me a few days to reply…been super busy. I’m not really sure why you would be getting login failed unless your user information in the database is not correct. I normally keep $this->Auth->allow(*); in my app controller until I can create a new user with each site. This verifies that the hash in the database will match the security salt I set in the config file.
This is awesome. Especially the update-password-only-if-filled-in part. Great work.
A bit of newbie question here, hopefully you can help out my confusion!?
‘required’ => true
‘allowEmpty’ => true
How does this work? the field value is required, and yet is allowed to be empty?
Aplogises if this is a really dumb question as I still learning!
Hi Kris,
I’m not sure which model you are referring to. It could either just be thrown in there out of habit so don’t let it confuse you. There are situations where that would be applicable though. If you have a field with multiple validations. You would want to continue added required to each validation rule otherwise not adding it to following rules will cause it to not be required. All ‘required’ really does is add a required class to the div element for styling. So it isn’t even really necessary. I hope that cleared things up for you.
nice article! after reading lots of posts over the inet, this was the most helpfull. just one question, is there some possibility, how express order of validation rules (because of messages)…