A Complete Login and Authentication Application Tutorial for CakePHP 2.3

in CakePHP/PHP/Tutorials & Samples/Web Development

Cake provides a very good tutorial on how to use the Auth component here, but its not complete. So, I spent a couple hours setting up a complete tutorial that you can download and check out a live demo. Here is what we will be creating: A web application that uses CakePHP’s Auth component to login and logout as well as bar access to certain pages if the user is not authorized. Once a user is logged-in, they will be able to go the dashboard and edit users. (Please note that I am not changing the default CakePHP theme. So below is what the login screen looks like:)

Edit: July 2014 Updates
Thanks to various reader inputs, I have updated the .zip file to fix some minor issues that were noticed. I also have a live demo that you can play with here. Fixes include:

  • fixed: deleted members can no longer login
  • fixed: error when you try to use an existing username or email again for a new user

login

Users Database Table

Let’s start by creating the users database table. The users table contains a user’s username, password and role. Additional fields are meta fields such as created and modified dates as well as a status field. (I never actually delete records, just turn their status to 0.) Here is what the final users table looks like:

CREATE TABLE users (
    `id` INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
    `username` VARCHAR(128),
    `password` VARCHAR(128),
    `email` VARCHAR(128),
    `role` VARCHAR(64),
    `created` DATETIME DEFAULT NULL,
    `modified` DATETIME DEFAULT NULL,
    `status` tinyint(1) NOT NULL DEFAULT '1'
);

Routes.php

Now, lets modify the core components of CakePHP to support our login module. First, we need to modify routes.php so that we can have a custom link for login, logout and the dashboard. This step is not required but I do it so that the URLs look clean..

	Router::connect('/dashboard', array('controller' => 'users', 'action' => 'index'));
	Router::connect('/login', array('controller' => 'users', 'action' => 'login'));
	Router::connect('/logout', array('controller' => 'users', 'action' => 'logout'));

We also need to modify the home page so that it now points to our login action.

	Router::connect('/', array('controller' => 'users', 'action' => 'login'));

User.php

Next, we need to create a file called User.php in the app\Model folder. This is our users model where all of our validation logic will be. To accomplish this, I used some of Cake’s buil-in validation rules as well as my own custom validation rules. My rules are pretty simple: Usernames must be unique, non-empty, alphanumeric and be between 5 and 15 characters. Passwords must have a minimum length of 6 and must match the confirmation password. Emails must be unique and be at least 6 characters in length. Finally, roles must be in the list of accepted roles that I have selected, which include: ‘king’, ‘queen’, ‘bishop’, ‘rook’, ‘knight’ and ‘pawn’. Some of the custom validation functions I created include isUniqueUsername() to determine if a username is unique, isUniqueEmail() to determine if an email is unique, alphaNumericDashUnderscore() to only allow alphanumeric values, equaltofield() to check if a value is equal to another value. You can learn more about CakePHP’s custom validation rules here. Finally, I had to alter the beforeSave() function so that I hash the passwords that I get before saving them. For security reasons, you should never store unencrypted passwords in your Database. Below is the full code for User.php

App::uses('AuthComponent', 'Controller/Component');

class User extends AppModel {
	
	public $avatarUploadDir = 'img/avatars';
    
	public $validate = array(
        'username' => array(
            'nonEmpty' => array(
                'rule' => array('notEmpty'),
                'message' => 'A username is required',
				'allowEmpty' => false
            ),
			'between' => array( 
				'rule' => array('between', 5, 15), 
				'required' => true, 
				'message' => 'Usernames must be between 5 to 15 characters'
			),
			 'unique' => array(
				'rule'    => array('isUniqueUsername'),
				'message' => 'This username is already in use'
			),
			'alphaNumericDashUnderscore' => array(
				'rule'    => array('alphaNumericDashUnderscore'),
				'message' => 'Username can only be letters, numbers and underscores'
			),
        ),
        'password' => array(
            'required' => array(
                'rule' => array('notEmpty'),
                'message' => 'A password is required'
            ),
			'min_length' => array(
				'rule' => array('minLength', '6'),  
				'message' => 'Password must have a mimimum of 6 characters'
			)
        ),
		
		'password_confirm' => array(
            'required' => array(
                'rule' => array('notEmpty'),
                'message' => 'Please confirm your password'
            ),
			 'equaltofield' => array(
				'rule' => array('equaltofield','password'),
				'message' => 'Both passwords must match.'
			)
        ),
		
		'email' => array(
			'required' => array(
				'rule' => array('email', true),    
				'message' => 'Please provide a valid email address.'    
			),
			 'unique' => array(
				'rule'    => array('isUniqueEmail'),
				'message' => 'This email is already in use',
			),
			'between' => array( 
				'rule' => array('between', 6, 60), 
				'message' => 'Usernames must be between 6 to 60 characters'
			)
		),
        'role' => array(
            'valid' => array(
                'rule' => array('inList', array('king', 'queen', 'bishop', 'rook', 'knight', 'pawn')),
                'message' => 'Please enter a valid role',
                'allowEmpty' => false
            )
        ),
		
		
		'password_update' => array(
			'min_length' => array(
				'rule' => array('minLength', '6'),   
				'message' => 'Password must have a mimimum of 6 characters',
				'allowEmpty' => true,
				'required' => false
			)
        ),
		'password_confirm_update' => array(
			 'equaltofield' => array(
				'rule' => array('equaltofield','password_update'),
				'message' => 'Both passwords must match.',
				'required' => false,
			)
        )

		
    );
	
		/**
	 * Before isUniqueUsername
	 * @param array $options
	 * @return boolean
	 */
	function isUniqueUsername($check) {

		$username = $this->find(
			'first',
			array(
				'fields' => array(
					'User.id',
					'User.username'
				),
				'conditions' => array(
					'User.username' => $check['username']
				)
			)
		);

		if(!empty($username)){
			if($this->data[$this->alias]['id'] == $username['User']['id']){
				return true; 
			}else{
				return false; 
			}
		}else{
			return true; 
		}
    }

	/**
	 * Before isUniqueEmail
	 * @param array $options
	 * @return boolean
	 */
	function isUniqueEmail($check) {

		$email = $this->find(
			'first',
			array(
				'fields' => array(
					'User.id'
				),
				'conditions' => array(
					'User.email' => $check['email']
				)
			)
		);

		if(!empty($email)){
			if($this->data[$this->alias]['id'] == $email['User']['id']){
				return true; 
			}else{
				return false; 
			}
		}else{
			return true; 
		}
    }
	
	public function alphaNumericDashUnderscore($check) {
        // $data array is passed using the form field name as the key
        // have to extract the value to make the function generic
        $value = array_values($check);
        $value = $value[0];

        return preg_match('/^[a-zA-Z0-9_ \-]*$/', $value);
    }
	
	public function equaltofield($check,$otherfield) 
    { 
        //get name of field 
        $fname = ''; 
        foreach ($check as $key => $value){ 
            $fname = $key; 
            break; 
        } 
        return $this->data[$this->name][$otherfield] === $this->data[$this->name][$fname]; 
    } 

	/**
	 * Before Save
	 * @param array $options
	 * @return boolean
	 */
	 public function beforeSave($options = array()) {
		// hash our password
		if (isset($this->data[$this->alias]['password'])) {
			$this->data[$this->alias]['password'] = AuthComponent::password($this->data[$this->alias]['password']);
		}
		
		// if we get a new password, hash it
		if (isset($this->data[$this->alias]['password_update']) && !empty($this->data[$this->alias]['password_update'])) {
			$this->data[$this->alias]['password'] = AuthComponent::password($this->data[$this->alias]['password_update']);
		}
	
		// fallback to our parent
		return parent::beforeSave($options);
	}

}

AppController.php

Next, AppController needs to be modified so that it uses Cake’s Auth component. This is where we tell the Auth component to redirect users to the index page after a successful login and to the login page after they logout. Once we do so, we need to update the beforeFilter() function to only allow the login action to be authorized in any controller. All other actions will only be accessible after the user is logged-in. I’ve also setup an isAuthorized() function that could be used to manage access to various pages. (The isAuthorized() function is not covered in this post, but its quite easy to setup one..)

	public $components = array(
		'DebugKit.Toolbar',
		'Session',
        'Auth' => array(
            'loginRedirect' => array('controller' => 'users', 'action' => 'index'),
            'logoutRedirect' => array('controller' => 'users', 'action' => 'login'),
			'authError' => 'You must be logged in to view this page.',
			'loginError' => 'Invalid Username or Password entered, please try again.'
 
        ));
	
	// only allow the login controllers only
	public function beforeFilter() {
        $this->Auth->allow('login');
    }
	
	public function isAuthorized($user) {
		// Here is where we should verify the role and give access based on role
		
		return true;
	}

UsersController.php

At this point, we can create our Users controller by creating a file called UsersController.php in app/Controller. This controler contains functions for login, logout, edit, index, add, edit and delete. There is also a function called activate, which is used to turn a user’s status back to active after they have been deleted. (remember that I don’t actually delete users. I just change their status flag). One important thing to note is that I override the beforeFilter() function defined in AppController so that I now allow login() and add() functions to be visible without requiring authorization. If we don’t do this, we will never be able to add users to our application. The rest of the controller is pretty straightforward and the full code is presented below:


class UsersController extends AppController {

	public $paginate = array(
        'limit' => 25,
        'conditions' => array('status' => '1'),
    	'order' => array('User.username' => 'asc' ) 
    );
	
    public function beforeFilter() {
        parent::beforeFilter();
        $this->Auth->allow('login','add'); 
    }
	


	public function login() {
		
		//if already logged-in, redirect
		if($this->Session->check('Auth.User')){
			$this->redirect(array('action' => 'index'));		
		}
		
		// if we get the post information, try to authenticate
		if ($this->request->is('post')) {
			if ($this->Auth->login()) {
				$this->Session->setFlash(__('Welcome, '. $this->Auth->user('username')));
				$this->redirect($this->Auth->redirectUrl());
			} else {
				$this->Session->setFlash(__('Invalid username or password'));
			}
		} 
	}

	public function logout() {
		$this->redirect($this->Auth->logout());
	}

    public function index() {
		$this->paginate = array(
			'limit' => 6,
			'order' => array('User.username' => 'asc' )
		);
		$users = $this->paginate('User');
		$this->set(compact('users'));
    }


    public function add() {
        if ($this->request->is('post')) {
				
			$this->User->create();
			if ($this->User->save($this->request->data)) {
				$this->Session->setFlash(__('The user has been created'));
				$this->redirect(array('action' => 'index'));
			} else {
				$this->Session->setFlash(__('The user could not be created. Please, try again.'));
			}	
        }
    }

    public function edit($id = null) {

		    if (!$id) {
				$this->Session->setFlash('Please provide a user id');
				$this->redirect(array('action'=>'index'));
			}

			$user = $this->User->findById($id);
			if (!$user) {
				$this->Session->setFlash('Invalid User ID Provided');
				$this->redirect(array('action'=>'index'));
			}

			if ($this->request->is('post') || $this->request->is('put')) {
				$this->User->id = $id;
				if ($this->User->save($this->request->data)) {
					$this->Session->setFlash(__('The user has been updated'));
					$this->redirect(array('action' => 'edit', $id));
				}else{
					$this->Session->setFlash(__('Unable to update your user.'));
				}
			}

			if (!$this->request->data) {
				$this->request->data = $user;
			}
    }

    public function delete($id = null) {
		
		if (!$id) {
			$this->Session->setFlash('Please provide a user id');
			$this->redirect(array('action'=>'index'));
		}
		
        $this->User->id = $id;
        if (!$this->User->exists()) {
            $this->Session->setFlash('Invalid user id provided');
			$this->redirect(array('action'=>'index'));
        }
        if ($this->User->saveField('status', 0)) {
            $this->Session->setFlash(__('User deleted'));
            $this->redirect(array('action' => 'index'));
        }
        $this->Session->setFlash(__('User was not deleted'));
        $this->redirect(array('action' => 'index'));
    }
	
	public function activate($id = null) {
		
		if (!$id) {
			$this->Session->setFlash('Please provide a user id');
			$this->redirect(array('action'=>'index'));
		}
		
        $this->User->id = $id;
        if (!$this->User->exists()) {
            $this->Session->setFlash('Invalid user id provided');
			$this->redirect(array('action'=>'index'));
        }
        if ($this->User->saveField('status', 1)) {
            $this->Session->setFlash(__('User re-activated'));
            $this->redirect(array('action' => 'index'));
        }
        $this->Session->setFlash(__('User was not re-activated'));
        $this->redirect(array('action' => 'index'));
    }

}

All that remains is creating our ctp files that match the actions in our controller. Here they are:

login.ctp

This is the main page that is used to login to the system. It requires a valid username and password combination.

<div class="users form">
<?php echo $this->Session->flash('auth'); ?>
<?php echo $this->Form->create('User'); ?>
    <fieldset>
        <legend><?php echo __('Please enter your username and password'); ?></legend>
        <?php echo $this->Form->input('username');
        echo $this->Form->input('password');
    ?>
    </fieldset>
<?php echo $this->Form->end(__('Login')); ?>
</div>
<?php
 echo $this->Html->link( "Add A New User",   array('action'=>'add') ); 
?>

add.ctp

This is the page that allows you to add new users to the system. It is available when you are logged-in and when you are logged-out. The password is required twice, like in any professional website and validation rules, set in Users.php are enforced

<!-- app/View/Users/add.ctp -->
<div class="users form">

<?php echo $this->Form->create('User');?>
    <fieldset>
        <legend><?php echo __('Add User'); ?></legend>
        <?php echo $this->Form->input('username');
		echo $this->Form->input('email');
        echo $this->Form->input('password');
		echo $this->Form->input('password_confirm', array('label' => 'Confirm Password *', 'maxLength' => 255, 'title' => 'Confirm password', 'type'=>'password'));
        echo $this->Form->input('role', array(
            'options' => array( 'king' => 'King', 'queen' => 'Queen', 'rook' => 'Rook', 'bishop' => 'Bishop', 'knight' => 'Knight', 'pawn' => 'Pawn')
        ));
		
		echo $this->Form->submit('Add User', array('class' => 'form-submit',  'title' => 'Click here to add the user') ); 
?>
    </fieldset>
<?php echo $this->Form->end(); ?>
</div>
<?php 
if($this->Session->check('Auth.User')){
echo $this->Html->link( "Return to Dashboard",   array('action'=>'index') ); 
echo "<br>";
echo $this->Html->link( "Logout",   array('action'=>'logout') ); 
}else{
echo $this->Html->link( "Return to Login Screen",   array('action'=>'login') ); 
}
?>

which produces this form if the user is logged-in:

add-user-loggedin

and this form if the user is logged-out:

add-user-loggedout

index.ctp

Index.ctp acts as my dashboard and can only be accessed when a user is logged-in. This is where the list of users is displayed. It also uses Cake’s paginator to display the data.

<div class="users form">
<h1>Users</h1>
<table>
    <thead>
		<tr>
			<th><?php echo $this->Form->checkbox('all', array('name' => 'CheckAll',  'id' => 'CheckAll')); ?></th>
			<th><?php echo $this->Paginator->sort('username', 'Username');?>  </th>
			<th><?php echo $this->Paginator->sort('email', 'E-Mail');?></th>
			<th><?php echo $this->Paginator->sort('created', 'Created');?></th>
			<th><?php echo $this->Paginator->sort('modified','Last Update');?></th>
			<th><?php echo $this->Paginator->sort('role','Role');?></th>
			<th><?php echo $this->Paginator->sort('status','Status');?></th>
			<th>Actions</th>
		</tr>
	</thead>
	<tbody>						
		<?php $count=0; ?>
		<?php foreach($users as $user): ?>				
		<?php $count ++;?>
		<?php if($count % 2): echo '<tr>'; else: echo '<tr class="zebra">' ?>
		<?php endif; ?>
			<td><?php echo $this->Form->checkbox('User.id.'.$user['User']['id']); ?></td>
			<td><?php echo $this->Html->link( $user['User']['username']  ,   array('action'=>'edit', $user['User']['id']),array('escape' => false) );?></td>
			<td style="text-align: center;"><?php echo $user['User']['email']; ?></td>
			<td style="text-align: center;"><?php echo $this->Time->niceShort($user['User']['created']); ?></td>
			<td style="text-align: center;"><?php echo $this->Time->niceShort($user['User']['modified']); ?></td>
			<td style="text-align: center;"><?php echo $user['User']['role']; ?></td>
			<td style="text-align: center;"><?php echo $user['User']['status']; ?></td>
			<td >
			<?php echo $this->Html->link(    "Edit",   array('action'=>'edit', $user['User']['id']) ); ?> | 
			<?php
				if( $user['User']['status'] != 0){ 
					echo $this->Html->link(    "Delete", array('action'=>'delete', $user['User']['id']));}else{
					echo $this->Html->link(    "Re-Activate", array('action'=>'activate', $user['User']['id']));
					}
			?>
			</td>
		</tr>
		<?php endforeach; ?>
		<?php unset($user); ?>
	</tbody>
</table>
<?php echo $this->Paginator->prev('<< ' . __('previous', true), array(), null, array('class'=>'disabled'));?>
<?php echo $this->Paginator->numbers(array(   'class' => 'numbers'     ));?>
<?php echo $this->Paginator->next(__('next', true) . ' >>', array(), null, array('class' => 'disabled'));?>
</div>				
<?php echo $this->Html->link( "Add A New User.",   array('action'=>'add'),array('escape' => false) ); ?>
<br/>
<?php 
echo $this->Html->link( "Logout",   array('action'=>'logout') ); 
?>

It produces this form:

dashboard

Edit.ctp

Edit allows you to edit data about a given user. In my case, I don’t allow users to change their username and their password only gets changed if they enter a value. (Most of these rules were inspired by the rules that WordPress has for users ) The code is below

<!-- app/View/Users/add.ctp -->
<div class="users form">
<?php echo $this->Form->create('User'); ?>
    <fieldset>
        <legend><?php echo __('Edit User'); ?></legend>
        <?php 
		echo $this->Form->hidden('id', array('value' => $this->data['User']['id']));
		echo $this->Form->input('username', array( 'readonly' => 'readonly', 'label' => 'Usernames cannot be changed!'));
		echo $this->Form->input('email');
        echo $this->Form->input('password_update', array( 'label' => 'New Password (leave empty if you do not want to change)', 'maxLength' => 255, 'type'=>'password','required' => 0));
		echo $this->Form->input('password_confirm_update', array('label' => 'Confirm New Password *', 'maxLength' => 255, 'title' => 'Confirm New password', 'type'=>'password','required' => 0));
		

		echo $this->Form->input('role', array(
            'options' => array( 'king' => 'King', 'queen' => 'Queen', 'rook' => 'Rook', 'bishop' => 'Bishop', 'knight' => 'Knight', 'pawn' => 'Pawn')
        ));
		echo $this->Form->submit('Edit User', array('class' => 'form-submit',  'title' => 'Click here to add the user') ); 
?>
    </fieldset>
<?php echo $this->Form->end(); ?>
</div>
<?php 
echo $this->Html->link( "Return to Dashboard",   array('action'=>'index') ); 
?>
<br/>
<?php 
echo $this->Html->link( "Logout",   array('action'=>'logout') ); 
?>

Here is a screenshot:

edit-user

Download it all

That concludes the tutorial. You can download the entire tutorial in zip format here.

Tags:

Mifty Yusuf is a Montreal-based software developer who enjoys playing with new web technologies as well as comic books and illustrations. He beleives that, no matter what the question is, the answer is always Batman!

233 Comments

  1. SOLVED !
    You need to add 1 (for ID) and maybe two additional (for created and modifield fields if you use it in your DB) values to $this->request->data.
    The form isn’t including these infos, so you need to force them.
    Hope it will help someonelse 🙂

    /* **********************
    ** Edition d’un service *
    *************************/
    public function edit($id = null) {

    if (!$id) {
    $this->Session->setFlash(‘Merci de fournir l\’ID du service.’, ‘msg_error’);
    $this->redirect(array(‘action’=>’index’));
    }

    $service = $this->Service->findById($id);
    if (!$service) {
    $this->Session->setFlash(‘L\’ID du service fournit est invalide.’, ‘msg_error’);
    $this->redirect(array(‘action’=>’index’));
    }

    if ($this->request->is(‘post’) || $this->request->is(‘put’)) {
    $this->Service->id = $id;
    if ($this->Service->save($this->request->data)) {
    $this->Session->setFlash(__(‘Le service a été mis à jour.’), ‘msg_success’);
    $this->redirect(array(‘action’ => ‘edit’, $id));
    }else{
    $this->Session->setFlash(__(‘Impossible de mettre à jour le service.’), ‘msg_error’);
    $this->request->data[Inflector::singularize($this->name)][‘id’] = $service[Inflector::singularize($this->name)][‘id’];
    $this->request->data[Inflector::singularize($this->name)][‘created’] = $service[Inflector::singularize($this->name)][‘created’];
    $this->request->data[Inflector::singularize($this->name)][‘modified’] = $service[Inflector::singularize($this->name)][‘modified’];

    // TEST, it will only print modified fields by user before error validations
    pr(array_diff_assoc($this->request->data[Inflector::singularize($this->name)], $service[Inflector::singularize($this->name)]));
    }
    }

    if (!$this->request->data) {
    $this->request->data = $service;
    }
    }

  2. Hi Mifty,

    it’s me again. I don’t know if it’s a bug, but whenever I edit a user without editing the password, the password value in the database gets changed to 6bad9332c3a47efa08c94849215f4b615afd74c5. I’ve reloaded your zip file again to make sure i didn’t screw it up with my additions (user profile pictures etc) . but the behavior still exists.

    The steps i did:

    * install your zip
    * ensure I can add a user
    * copy the password value from this user
    * edit the user (but don’t change any value) and press the “edit user” button
    * search for the password value in the database

    Could you shed a light on it? thanks a million, your tutorial helped me a lot so far.

  3. This tutorial was… how do you say it? Relevant!! Finally I have
    found CakePHP tutorial that helped me. Thanks a lot!

  4. Useful info. Fortunate me I discoovered your websie by chance, and I’m stunned whhy this accident did noot took
    place earlier! I bookmarked it.

  5. I downloaded application but it’s not working when i click on add new user link. I am getting the error 404. Please let me know if i do need to change anything.

  6. Hi,
    I am fresher in cakephp and i was feeling very difficult about how i will learn cakephp.
    Then i searched your blog i got best result about this tuts.
    This is awesome for anyone who want to understand cakephp.

    Thanks

  7. I copied ur code and tried to work,, All works fine but it says username and password error.. Registration is getting updated.. Why its saying invalid name and passsword when i gave the right input

  8. Nice Work Mifty….But Could you give me a hint….Everthing works ok on my local WampServer but when I testing on a hosting (production enviroment) I receive a Blank page on Accions with permisions instead of login page….

    • Hi adolfo,
      The first thing to do is to open config.php and turn the debug value to 2 or 1. I konw that this is not ideal in a production setting but this will allow you to see exactly what error is causing the blank page. Remember that when you have debug set to 0 (as it should be in a production environment), all errors are suppressed and hidden…

  9. Hi Mifty,

    This is a great tutorial. It helps a lot. My question is that I dont really notice any differences in the access level that each role has. could you provide some code about that to explain how access levels are manageable. For example an admin can do anything delete edit update. A regular user can only see his posts
    Thanks

    • The access level is a flag to help you do special things within your code. These special things could be at the controller level or the view level.
      So, for example, you could check the logged-in user to determine his role and maybe show him a different layout (for example, you might have a layout for admins that is different than for regular users). Another example is maybe you may have a function called delleteAllCats() that is only available to administrators. So, in this case, you can check to see if the person trying to access this page is an administrator and let them have access to the function or reject them because they are not an admin.

  10. Hola Mifty. Tengo problemas con la asignacion de roles, no me queda claro donde tengo que hacer la validacion. ademas tengo problemas con la activacion y desactivacion de usuarios, cuando desactivo un usuario y hago el login el CRUD me deja ingresar. Por fa necesto ayuda

  11. I followed the instructions literally and somehow I am getting this error (using cakePHP 2.5.4):

    Fatal error: Call to a member function allow() on a non-object in C:\WAMP\www\site\app\Controller\AppController.php

    // only allow the login controllers only
    public function beforeFilter() {
    $this->Auth->allow(‘login’);
    }

  12. hi Yusaf,

    This code is not working properly.before save the user data use AuthComponents to encript the user pass word.
    and change in add user method.

    Crrect code is here

    public function add() {
    if ($this->request->is(‘post’)) {
    $this->User->create();
    $data = $this->request->data;
    $data[‘User’][‘password’] = AuthComponent::password($data[‘User’][‘password’]);
    if ($this->User->save($data)) {
    $this->Session->setFlash(__(‘The user has been created’));
    $this->redirect(array(‘action’ => ‘index’));
    } else {
    $this->Session->setFlash(__(‘The user could not be created. Please, try again.’));
    }
    }
    }

    • Hi Tanseer,
      Actually, my code is 100% correct. The Auth Component is hashing the password. Instead of doing the hashing in the add() method of the controller, it is done inside the beforeSave() function of the User model. This is a better way to do it since it guarantees that this piece of code will always get executed every time we save a user. The way it is currently implemented, I would not need to add any additional code if I created a function called edit() or super_save() in the controller since my beforeSave() would always be called in all these functions. But if I did it your way, I would have to copy over the hashing code to each and every one of those functions which means that I am copy/pasting code and opening myself up to potential errors.

  13. Hello mifty, do u mind to create some simple isAuthorized code since i try to create isAuthorized to limit the access for admin only able to access edit and delete but seems like nothing happen. Here i share some of the isAuthorized code:

    in AppController:
    public function isAuthorized($user) {
    if (isset($user[‘role’]) && $user[‘role’] === ‘admin’) {
    return true;
    }
    return false;
    }

    UsersController:
    public function isAuthorized($user = null) {
    switch($this->action) {
    case “index”:
    case “add”:
    if ($user[‘role’] == ‘admin’) {
    return true;
    }
    break;

    case “view”:
    case “edit”:
    case “delete”:
    $id = $this->request->params[‘pass’][0];
    $this->User->id = $id;
    if ($user[‘role’] == ‘admin’ && $this->User->field(‘user_id’) == $user[‘user_id’]) {
    return true;
    }
    break;
    }
    return parent::isAuthorized($user);
    }

    • Hi Joe, I would suggest you start off with something real simple. The isAuthorized() function is only used for determining if a user is authorized to do stuff with a controller. In here, you should only be checking the user’s role. The actual logic of what to do should be handled in the controller itself. So, in your UsersController, try the following piece of code:

      &lt;?php
      	public function isAuthorized($user = null) {
      		switch($this-&gt;action) {
      			case &quot;index&quot;:
      			case &quot;add&quot;:
      			case &quot;edit&quot;:
      			case &quot;delete&quot;:
      			if ($user['role'] == 'admin') {
      				return true;
      			}
      			break;
      			
      			default:{
      				return parent::isAuthorized($user);
      			}
      		}
      	}
      	
      	public function delete($id){
      		$this-&gt;User-&gt;id = $id;
      		// do whatever you want to do next...
      	}
      ?&gt;
      
  14. Hi .. i m new to cakephp .. i need Your help ..! How to create joining results from two tables in cake php…? i want show table1 and table2 value in index.ctp after login .. what i do this place ? $this->set(compact(‘users’));

  15. I am learning Cakephp.
    I am fresher in IT industry.
    super awesome tutorial mifty
    This one of the best tuts ever i have seen
    you do awesome stuff when u are bored
    Thanks a lot!!

  16. Hi Mifty

    A great piece of work, I have found very useful.

    I did pick up on one bug, which was also highlighted by Henk on July 19, where when editing a user if the password is left blank the User data is overwritten with a hashed version of a blank password. This may be due to 2.5, just don’t know. I have made some changes to ensure that if password is blank then only the new email is written (if indeed that has been updated), and thought I would share:

    public function edit($id = null) {

    if (!$id) {
    $this->Session->setFlash(‘Please provide a user id’);
    $this->redirect(array(‘action’=>’index’)); //need to change this for redirect to page it came from
    }

    $user = $this->User->findById($id);
    if (!$user) {
    $this->Session->setFlash(‘Invalid User ID Provided’);
    $this->redirect(array(‘action’=>’index’)); //check
    }

    if ($this->request->is(‘post’) || $this->request->is(‘put’)) {
    $this->User->id = $id;

    if (!$this->data[‘User’][‘password_update’]) { // check if password is empty

    // just save updated email as nothing else has changed, first check it is new

    $newemail = $this->data[‘User’][’email’];
    if ($newemail == $user[‘User’][’email’]) {
    $this->Session->setFlash(__(‘No changes made!’));
    } else {
    $this->User->saveField(’email’, $newemail);
    $this->Session->setFlash(__(‘The user email has been updated’));
    $this->redirect(array(‘action’ => ‘index’, $id));
    }
    } else { // not empty so save all new data

    if ($this->User->save($this->request->data)) {
    $this->Session->setFlash(__(‘The user has been updated’));
    $this->redirect(array(‘action’ => ‘index’, $id));
    } else {
    $this->Session->setFlash(__(‘Unable to update your user.’));
    }
    }
    }

    if (!$this->request->data) {
    $this->request->data = $user;
    }
    }

    I am sure I could have written it better, but it works just fine.

    Thanks Again.

    • Hi tom! Thanks so much for sharing your modified code. I hope this will help someone else and I will update the code whenever I get a chance.

  17. Hello Mifty,

    Thank you for the great tutorial.

    I got the login screen up and running, but when i click the link to add a user i see this error:

    Missing Controller

    Error: Users.AddController could not be found.

    Error: Create the class AddController below in file: /Applications/XAMPP/xamppfiles/htdocs/cake/app/Plugin/Users/Controller/AddController.php

    I used all your files, so what am i doing wrong?

    • Hello Misty,

      O figured out that when i add /users/add to routes php and set the action to add it works.

      But is this really necessary? That would meen i have to add these rules for every action?

      • Hi bad,
        You should not have to modify your routes every time that you add a new action. This sounds like something is wrong with your setup. What exactly did you change in routes.php?

        • Hi Mifty,

          I started all over again because i was making a mess of it. A whole fresh CakePHP installation.

          But the same thing. I followed your tutorial. I didn’t change anything in de routes.php. Only what you said in your tutorial.

          But still it only works when i add /users/add to the routes.php. You can follow the given url in this post to see what happens.

Leave a Reply

Your email address will not be published.

*

Latest from CakePHP

Go to Top