- Home
- >> Nerd Digest
- >> PHP
-
Login Form and Authentication Application with Server Side Validation in cakephp
over 8 years ago
A Login Form that uses cakephp auth component to login and logout and access is denied if user is not authorized.
step 1: users database table.
First create users table in your database:
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' );
step 2: Routes.php
Modify routes.php so that we can have custom link for login , logout and dashboard
Router::connect('/dashboard', array('controller' => 'users', 'action' => 'index')); Router::connect('/login', array('controller' => 'users', 'action' => 'login')); Router::connect('/logout', array('controller' => 'users', 'action' => 'logout')); Router::connect('/', array('controller' => 'users', 'action' => 'login'));
step 3: User.php
Next, we will create a file User.php in the app\Model folder. This is our users model where we will write all our validations and logics. I used some of Cakephp inbuilt validation rules as well as my own custom validation rules. My rules are very 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.
I have created functions isUniqueUsername() to find out if a username is unique or not, isUniqueEmail() to find out if an email is unique, alphaNumericDashUnderscore() to only allow alphanumeric values, equaltofield() to check if password is equal to confirm password. At the end I altered beforeSave() function so that I can hash the passwords before saving it into the database. The code is written below.
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); } }
step 4: AppController.php
Now add the following lines of code in your AppController:
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; }
step 5: UsersController.php
Next, we will create a file UsersController.php in app/Controller. This file contains functions for login, logout, edit, index, add, edit and delete. There is also a function called activate, which is used to activate or deactivate users. I have override the beforeFilter(), so that I can allow login() and add() functions. The code is written 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')); }
step 6: login.ctp
This is the login page that is used to login to the system.
<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>need to <?php echo $this->Form->end(__('Login')); ?> </div> <?php echo $this->Html->link( "Add A New User", array('action'=>'add') ); ?>
step 7: add.ctp
This is the page that allows you to add new users. It is available when you are logged-in. When your are logged out you can not access this page.
<!-- 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') ); } ?>
step 8: index.ctp
index.ctp is the dashboard and you can access the dashboard only when you are logged in.
<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') ); ?>
step 9: Edit.ctp
Edit allows you to change user details, you can change all other details except username. The code is written 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') ); ?>
0 Comment(s)