CakePHP Authentication

Identifying, authenticating and authorizing users is a common part of almost every web application. In CakePHP AuthComponent provides a pluggable way to do these tasks. AuthComponent allows developer to combine authentication objects, and authorization objects to create flexible ways of identifying and checking user authorization. There are few steps to complete the authetication process in CakePHP starting with username & password input validation in User.php as follows:
'username' => array(
            'notBlank' => array(
                'rule' => array('notBlank'),
                'message' => 'This field is required',
            ),
            'lengthBetween' => array(
                'rule' => array('lengthBetween',5,15),
                'message' => 'Username must be Between 5 to 15',
            ),
            'unique' => array(
                'rule'    => 'isUnique',
                'message' => 'This username has already been registered.'
            )
        ),
'password' => array(
            'notBlank' => array(
                'rule' => array('notBlank'),
                'message' => 'This field is required',
            ),
            'minLength' => array(
                'rule' => array('minLength',8),
                'message' => 'Minimum 8 characters',
            ),
        ),

Password Hashing
All passwords should be hash/encrypted before saving the value into database to ensure user password is not stored as plain text in database. For the hahsing algorithm, it is strongly recommended to use BlowfishPasswordHasher. It uses a stronger hashing algorithm (bcrypt) than SimplePasswordHasher (sha1) and provides per user salts. To hash the password value, navigate to user model at …app/Model/User.php and add the following:

<?php
App::uses('AppModel', 'Model');
App::uses('BlowfishPasswordHasher', 'Controller/Component/Auth');

class User extends AppModel {
public function beforeSave($options = array()) {
    if (isset($this->data[$this->alias]['password'])) {
        $passwordHasher = new BlowfishPasswordHasher();
        $this->data[$this->alias]['password'] = $passwordHasher->hash(
            $this->data[$this->alias]['password']
        );
    }
    return true;
}

 

Session redirect
To control the redirect after login and logout, developer need to identify the redirect pages and allow certain pages to be public view for example the login and registration page. In CakePHP, the public function beforeFilter() is used to identify which pages that not required Auth to access it. During the login process, system will check the condition for user status either the account is active(1) or not(0). All registered account will be treated as active and marked in database User.status==1 and inactive account will be mark as User.status==0 which means that the user account has been disable by the administrator or moderator. To manage the redirect, navigate to user controller at …app/Controller/usersController.php and add the following codes. 

class UsersController extends AppController {
public function beforeFilter() {
    parent::beforeFilter();
        $this->Auth->allow('login','add'); //Allow pages
        $this->Auth->logoutRedirect = array('controller'=>'users','action'=>'login');
    }
    
    public function login() {
        $this->set('title_for_layout', 'EDMS: Electronic Document Management System');
        if($this->Session->check('Auth.User')){
            $this->redirect(array('controller'=> 'users', 'action' => 'index'));      
        }      
        if ($this->request->is('post')) {
            if ($this->Auth->login()) {
                $status = $this->Auth->user('status');
            if ($status != 1){
            $this->Session->setFlash(__('Sorry, your account is not active'),'default',array('class'=>'alert alert-warning'));
            $this->redirect($this->Auth->logout());
        }
            $this->redirect($this->Auth->redirectUrl());
        } else {
            $this->Session->setFlash(__('Invalid username or password'),'default',array('class'=>'alert alert-danger'));
            }
        }       
    }

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


Auth component

Auth component is a class responsible for requiring login for certain actions, handling user sign-in and sign-out, and also authorizing logged in users to the actions they are allowed to reach. To add this component to your application open your ...app/Controller/AppController.php file and add the following lines:

class AppController extends Controller {
    public $helpers = array(
        'Form'=> array('className' => 'BootstrapForm'), 
        'Html'=> array('className' => 'BootstrapHtml'),
    );

    public $components = array(
        'Session',
        'Auth'=>array(
            'loginRedirect'=>array('controller'=>'users', 'action'=>'index'),
            'logoutRedirect'=>array('controller'=>'users', 'action'=>'logout'),
            'authError'=>"Sorry, you are not allow to view the content. Please login.",
            'authorize'=>array('Controller'),
            'authenticate' => array('Form' => array('passwordHasher' => 'Blowfish')),
        )
    );
    
    public function beforeFilter() {
        $this->layout = 'bootstrap';
        $this->Auth->allow('login','add');
        $this->Auth->allow(array('controller' => 'pages', 'action' => 'display'));
        $this->set('current_user', $this->Auth->user());
        $this->set('logged_in', $this->Auth->loggedIn());
        $this->Auth->logoutRedirect = array('controller'=>'users','action'=>'login');   
    }

    public function isAuthorized($user) {
        return true;
    }
}


Login Page
Login page provide interface for user to key-in their username and password. To create the interface, create a new file with name login.ctp and save it into folder User View at ...app/View/Users/login.ctp with the following codes inside it.

<div class="panel panel-default">
    <div class="panel-heading">EDMS Log-in</div>
        <div class="panel-body">
<?php echo $this->Form->create('User'); ?>
<fieldset>
    <?php echo $this->Form->input('username', array(
            'class' => 'form-control', 
            'label' => 'Username')); ?>
    <?php echo $this->Form->input('password', array(
            'class' => 'form-control', 
            'label' => 'Password')); ?>
</fieldset>
<div class="form-group">
<?php echo $this->Html->link(__('Register'), 
    array('controller' => 'users', 'action' => 'add'),
    array('class'=>'btn btn-warning',  'escape' => false)); ?>
<?php echo $this->Form->button(__('Log in'), array(
    'type' => 'submit', 
    'class' => 'btn btn-primary',
    'escape' => false));?>
</div>
        </div>
</div>


Account status control
The role attribute is used to identify either the account is active or not. It is important to not delete the user account as there is a relationship between user table and others tables for instance if the user has upload a document, then administrator delete the account, it is not possible to know who are the uploader of the document since the account has been deleted. To manage this issues, it is recommended to control using account status which is if the User.status==1 indicate that the account is active and vice versa if User.status==0. Only account with active (1) status can logged-in into the application. In the usersController.php at ...app/Controller/userController.php add this line of code after public function delete as shown below:

public function deactivate($id=null) {
        if (!$id) {
        $this->Session->setFlash(__('User account not valid'), 'default', array('class' => 'alert alert-warning'));
        return $this->redirect(array('action' => 'view', $this->User->id));
    }
        $this->User->id = $id;
        if ($this->User->saveField('status', 0)) {
        $this->Session->setFlash(__('User account has been De-Activated'), 'default', array('class' => 'alert alert-danger'));
        return $this->redirect(array('action' => 'view', $this->User->id));
    }
        $this->Session->setFlash(__('User account was not De-Activated'), 'default', array('class' => 'alert alert-warning'));
        return $this->redirect(array('action' => 'view', $this->User->id));
    }
 
public function activate($id=null) {
        if (!$id) {
        $this->Session->setFlash(__('User account not valid'), 'default', array('class' => 'alert alert-warning'));
        return $this->redirect(array('action' => 'view', $this->User->id));
    }
        $this->User->id = $id;
        if ($this->User->saveField('status', 1)) {
        $this->Session->setFlash(__('User account has been Re-Activated'), 'default', array('class' => 'alert alert-success'));
        return $this->redirect(array('action' => 'view', $this->User->id));
    }
        $this->Session->setFlash(__('User account was not Re-Activated'), 'default', array('class' => 'alert alert-warning'));
        return $this->redirect(array('action' => 'view', $this->User->id));
    }


The public function deactivate is use to disable unwanted user account and the public function activate is to enable any account that has been disable. To complete this action, it is necessary to have a direct access activate/de-activate button for administrator to manage the user account status. It is recommended to display the activation button in view.ctp. In ...app/View/Users open file view.ctp and add the following codes to generate button for administrator to change the user account status.

<li>
<?php if ($current_user['role'] == 'Administrator'): ?>  
    <?php
        if($user['User']['status'] != 0){ 
echo $this->Html->link('<i class="glyphicon glyphicon-ban-circle"></i> ' .__('Disable Account'), 
array('action' => 'deactivate', $user['User']['id']),
array('escape' => false)); 
} else {
echo $this->Html->link('<i class="glyphicon glyphicon-ok-circle"></i> ' .__('Enable Account'), 
array('action' => 'activate', $user['User']['id']),
array('escape' => false)); 
        }
    ?>
<?php endif; ?>  
</li>


That all. Happy programming guys :)