Secure CakePHP via Sessions & Magic (Login / Logout)

Making sure a CakePHP application is secure is a total snap thanks to “sessions” - the rock animal of websites. Put on your All-Stars and boot up your MacBook - I’m about to go Discovery Channel on your ass.

Hopefully by the end of reading this article, you’ll be able to create a secure CakePHP application. The point is to allow only registered users access to restricted areas of your application without blocking access to all areas of your application.

Pretext

We’ll be creating three sections in order to achieve our goal of total security:

1: /app/app_controller.php
2: /app/controllers/users_controller.php
3: /app/views/users/
      -> add.thtml, edit.thtml, index.thtml, login.thtml, logout.thtml

As always, all of these sections can be downloaded so you can follow along.

1. The app_controller

Our app_controller.php file will hold the function checkSession which will check session data to make sure a user is logged in. Here’s the function in its entirety:

function checkSession(){

	// fill $username with session data
	$username = $this->Session->read('user');

	// if the $username is empty,
	// send user to login page
	if (!$username){
		$this->redirect('/users/login');
		exit();
	} else {
		// if $username is not empty,
		// check to make sure it's correct
		$results = $this->User->findByEmail($username);

		// if not correct, send to login page
		if(!$results){
			$this->Session->delete('user');
			$this->Session->setFlash('Incorrect session data.');
			$this->redirect('/users/login');
			exit();
		}

		// otherwise set $user variable as users email address
		$this->set('user', $results['User']['email']);
	}
}

The commenting throughout the above code is pretty self-explanatory - the session data is checked and validated. Score one for us.

2. The users_controller

Of the six functions in users_controller.php, we’ll cover the login function. It’s purpose is to check user-submitted data against a database, and either set a session (success) or redirect the user to the login page (failure) for another login attempt.

function login() {
	$this->set('error', false);
	if ($this->data) {
		// check submitted email address against database
		$results = $this->User->findByEmail($this->data['User']['email']);
		if ($results && $results['User']['password'] == md5($this->data['User']['password'])) {
			// set "user" session equal to email address
			$this->Session->write('user', $this->data['User']['email']);
			// set "last_login" session equal to users last login time
			$this->Session->write('last_login', $results['User']['last_login']);
			$results['User']['last_login'] = date("Y-m-d H:i:s");
			// save last_login date
			$this->User->save($results);
			$this->redirect('/');
		} else {
			// login data is wrong, redirect to login page
			$this->Session->setFlash('Wrong username / password. Please try again.');
			$this->redirect('/users/login');
		}
	}
}

The commented code above should be enough to grasp an understanding of how $this->Session works. It’s a simple CakePHP method of setting/deleting/reading sessions.

Secure Your Gear

Now that you’ve got the code to secure your Cake pages, you need to use it. Call the checkSession function to whenever you’d like to require a user to be logged in.

<?php
class ExampleController extends AppController  {
	var $name = "Example";
	var $helpers = array('Html');

	function index() {
		// make sure we're logged in
		$this->checkSession();

		// when viewing /app/views/examples/index.thtml
		// the user will be redirected to the login page
		// unless he's logged in, in which case he'll
		// see the page as normal
	}

	function example() {
		// when viewing /app/views/examples/example.thtml
		// everyone (logged in or not) will see this page
	}
}	

But what if you want to secure all the pages in a controller? Simple! Use Cake’s beforeFilter function:

<?php
class ExampleController extends AppController  {
	var $name = "Example";
	var $helpers = array('Html');

	function beforeFilter() {
		$this->checkSession();
	}

	function index() {
		// when viewing /app/views/examples/index.thtml
		// the user will be redirected to the login page
		// unless he's logged in, in which case he'll
		// see the page as normal
	}

	function example() {
		// when viewing /app/views/examples/example.thtml
		// the user will be redirected to the login page
		// unless he's logged in, in which case he'll
		// see the page as normal
	}
}	

Download The Package

Make sure you grab the complete package to see working examples of this article. A .sql file has been included for easy setup of the required MySQL users table.

Download the ‘Secure CakePHP via Sessions’ package and consider yourself cool.

13 Comments so far

  1. Martin on November 14th, 2007

    maybe you could a little plugin with it :)
    http://manual.cakephp.org/chapter/plugins

  2. Brad on December 3rd, 2007

    More fine-grained control can be obtained using ACL, which is described in the cake manual (applicable to 1.1) and numerous tutorials (1.1 & 1.2, YMMV).

  3. Chris on January 7th, 2008

    Thanks a lot man, works like a charm :)

  4. Jay on January 13th, 2008

    It works very well! :) Thanks

  5. filchiprogrammer on February 18th, 2008

    Hi,

    is this also running on cakephp 1.2 version?

  6. Gaz on March 15th, 2008

    Yes this works on cakephp 1.2

  7. karim on April 20th, 2008

    You should add some salt to the md5 :)

    
    if ($results && $results['User']['password'] == md5($this->data['User']['password'].'somesalt'))
    

    and add ’somesalt’ when you create the user’s record (add action for eg.)

  8. jdm on April 24th, 2008

    I am still a beginner of this,i find difficulty in understanding it..
    I downloaded the package but errors are coming out..Please help me with this.

    Please explain me why are there errors? What’s wrong with this?

    
    Errors:
    - Warning (512): Method HtmlHelper::formTag does not exist [CORE/cake/libs/view/helper.php, line 148]
    - Warning (512): Method HtmlHelper::inputTag does not exist [CORE/cake/libs/view/helper.php, line 148]
    - Notice (1024): Method tagErrorMsg() is deprecated in HtmlHelper: see FormHelper::error [CORE/cake/libs/view/helpers/html.php, line 801]
    - Warning (512): Method HtmlHelper::passwordTag does not exist [CORE/cake/libs/view/helper.php, line 148]
    - Warning (512): Method HtmlHelper::submitTag does not exist [CORE/cake/libs/view/helper.php, line 148]
    
  9. Javier on April 26th, 2008

    The code works very well, thanks a lot!

  10. dave on May 1st, 2008

    jdm,

    I’m not sure, but it seems like you are using the wrong version of CakePHP. There are certain tasks that were moved from the html helper to the form helper, I am a beginner too so I may be 100% wrong, but those warnings look like the ones I got when I went from Cake 1.1 to Cake 1.2. The helpers should be there, you just may have to replace $html-> with $form->. Again, I may be wrong, but give it a try.

  11. ahac on May 7th, 2008

    jdm: You are probably using Cake 1.2 (which has new form helpers) while this is written for 1.1.

  12. jdm on May 15th, 2008

    Thanks 4 letting me about helpers….

  13. Piotr Kaleta on July 30th, 2008

    Hi

    I must say that i’m pretty confused. I treid to work with session&cakephp&redirect and I always ended with erased sesion after redirecting to another controler.

    Although, what do you think about putting some nice ” exit();” after $this->redirect? consider that beacuse when you are redirecting the script is still working

Leave a Reply