In this article I'm going to create a simple user authentication system whereby users will have to login to access any admin controller action. This is quite a basic application so I'm using the Session route of identifying a logged in user instead of the ACL route.
Users Controller
The Users Controller will deal with logging in and logging out users from the system so I'm going to have a separate action for each, I'm also going to include an index action which will just redirect the user to the login page.- class UsersController extends AppController {
- // name variable
- var $name = 'Users';
- // load any helpers used in the views
- var $helpers = array('Html', 'Form');
- /**
- * index()
- * main page for users
- * url: /users/index
- */
- function index() {
- // redirect to login page
- $this->redirect('login');
- }
- /**
- * index()
- * login page for users
- * url: /users/login
- */
- function login() {
- }
- /**
- * logout()
- * logs out a user
- * url: /users/logout
- */
- function logout() {
- }
- }
Logging In
The first thing I need to create is a login view that will display the form so that a user can enter a username and password. I've taken a different approach to this form and manually created the surrounding div tag and form label instead of using the $form->input() to build everything for me.- // file: /app/views/users/login.ctp
- <div class="login form">
- <?php if(isset($error)): ?>
- <p class="flash_bad">
- <?php e($error); ?>
- </p>
- <?php endif; ?>
- <?php echo $form->create('User', array('url'=>'login'));?>
- <fieldset>
- <legend>Login</legend>
- <div class="input required">
- <label>Username: *</label>
- <?php echo $form->text('User.username'); ?>
- </div>
- <div class="input required">
- <label>Password: *</label>
- <?php echo $form->password('User.password'); ?>
- </div>
- </fieldset>
- <?php echo $form->end('Login');?>
- </div>
If the username/password are both ok then I'm going to save the user data in a session and I will use this session to check that a user is logged in. After the session is saved the user is redirected to the admin_index() of the DVDs Controller.
- // file: /app/controllers/users_controller.php
- function login() {
- // if the form has been submitted
- if(!empty($this->data)) {
- // check the username and password
- if( ($user = $this->User->check_login($this->data)) ) {
- // save the user information to the session
- $this->Session->write('User', $user);
- // set flash messsage
- $this->Session->setFlash('You have successfully logged in.', 'flash_good');
- // redirect the user
- $this->redirect('/admin/dvds/');
- } else {
- // set error message
- $this->set('error', 'ERROR: Invalid Username or Password.');
- }
- }
- }
The User Model
The User Model is setup to use the "admins" table in the database. This table will store the username and an md5 hashed password of all the users that will have access to the application. The "useTable" variable is used to change the default table that the Model connects to.The check_login() functions takes the form data passed from the Controller and tries to find the user in the database. The passwords are then compared and if everything was ok the user data from the database is passed back to the Controller.
- <?php
- // file: app/model/user.php
- class User extends AppModel {
- var $name = 'User';
- var $useTable = 'admins';
- /**
- * check_login()
- * checks the username and password against the database
- */
- function check_login($data) {
- // init
- $valid = false;
- // find user from the database with the username
- $user = $this->find('first', array(
- 'conditions' => array(
- 'User.username'=>$data['User']['username']
- )
- ));
- // if the passwords match
- if($user['User']['password'] == md5($data['User']['password'])) {
- $valid = $user;
- }
- return $valid;
- }
- }
- ?>
Checking a User is Logged In
In order to check that a user is logged in to the application I can check in the Session for a variable called "User". If it exists I can assume the user has successfully logged in, if not I can redirect the user to either the login page or the main DVDs page.In all the Controllers I can use the beforeFilter() function, which will run before any of the actions in the Controller are processed. This enables me to call a function that will check for the Session variable. The params['admin'] is just a global array that will indicate if an admin action has been requested and if so I want to check that a user is logged in.
- // file: /app/controllers/dvds_controller.php
- /**
- * beforeFilter()
- * this is called before any action in the controller
- */
- function beforeFilter() {
- // if an admin action has been called
- if(isset($this->params['admin']) && $this->params['admin']) {
- // check that a user is logged in
- $this->check_user();
- }
- }
- // file: /app/app_controller.php
- /**
- * check_user()
- * checks that a user is logged in
- */
- function check_user() {
- // get user data from session
- $user = $this->Session->read('User');
- // if empty
- if(empty($user)) {
- // set a flash message
- $this->Session->setFlash('ERROR: You must be logged to access the admin area.', 'flash_bad');
- // redirect user
- $this->redirect(array('action'=>'login', 'controller'=>'users', 'admin'=>false));
- }
- }
Make sure you place the beforeFilter() method inside any Controller that you want to restrict access to or alternatively you can place it inside your app_controller.php file to make it run before every Controller in your application which is quite useful.
Logging Out
Because I'm using the user data in the Session to determine if a user is logged in or not I can simply delete this variable from the Session and redirect the user to the login page. The logout action does not require a View file because there is nothing to do display, the user is simply redirected.- // file: /app/controllers/users_controller.php
- function logout() {
- // delete the User session
- $this->Session->delete('User');
- // set flash message
- $this->Session->setFlash('You have successfully logged out.', 'flash_good');
- // redirect the user
- $this->redirect(array('action'=>'login', 'controller'=>'users'));
- }
Wrapping Up
This has been a very simple way to create an admin section with CakePHP, you could use the more advanced ACL or Auth Component but I haven't had much experience with either so for a simple online application this authentication will be sufficient. I've covered writing to and reading from CakePHP Sessions, creating a custom function in a Model and using the beforeFilter() function to run a bit of logic before any action in the Controller.CakePHP has a number of other callback functions along with beforeFilter() and these include:
- beforeRender()
- afterFilter()
- afterRender()