CakePHP: Authentication Setup on an Application

0
145
11 min read

 

CakePHP 1.3 Application Development Cookbook

CakePHP 1.3 Application Development Cookbook

Over 70 great recipes for developing, maintaining, and deploying web applications

        Read more about this book      

(For more resources on CakePHP, see here.)

Introduction

The first two recipes show us how to set up a basic, yet fully working authentication system. The next three recipes allow our users to log in using different information, have their user details saved after a successful login, and show us how to get this user information.

Setting up a basic authentication system

The first task to be completed when we are in the process of adding authentication to an application is to identify which controllers will need user access. Normally we would make every controller and action protected by default, and then we would specify which areas of our application allow public access.

Getting ready

We must have a users table that should contain, at least, two fields: username (to hold the username) and password (to hold a hash made out of the user’s password).

If you don’t have a table for this purpose, you can use the following SQL statement to create it:

CREATE TABLE `users`(
`id` INT UNSIGNED AUTO_INCREMENT NOT NULL,
`username` VARCHAR(255) NOT NULL,
`password` CHAR(40) NOT NULL,
PRIMARY KEY(`id`)
);

How to do it…

  1. Create a file named users_controller.php and place it inside your app/controllers folder with the following contents:

    <?php
    class UsersController extends AppController {
    public function login() {
    }
    public function logout() {
    $this->redirect($this->Auth->logout());
    }
    }
    ?>

  2. Create a file named login.ctp in your app/views/users folder (create the folder if you don’t have one already), and add the following contents:

    <?php
    echo $this->Form->create(array('action'=>'login'));
    echo $this->Form->inputs(array(
    'legend' => 'Login',
    'username',
    'password'
    ));
    echo $this->Form->end('Login');
    ?>

  3. Create a file named app_controller.php in your app/ folder with the following contents:

    <?php
    class AppController extends Controller {
    public $components = array(
    'Auth' => array(
    'authorize' => 'controller'
    ),
    'Session'
    );
    public function isAuthorized() {
    return true;
    }
    }
    ?>

  4. Modify the UsersController, and add the following code before the login method:

    public function beforeFilter() {
    parent::beforeFilter();
    $this->Auth->allow('add');
    }
    public function add() {
    if (!empty($this->data)) {
    $this->User->create();
    if ($this->User->save($this->data)) {
    $this->Session->setFlash('User created!');
    $this->redirect(array('action'=>'login'));
    } else {
    $this->Session->setFlash('Please correct the
    errors');
    }
    }
    }

  5. Create a file named add.ctp and place it in your app/views/users folder with the following contents:

    <?php
    echo $this->Form->create();
    echo $this->Form->inputs(array(
    'legend' => 'Signup',
    'username',
    'password'
    ));
    echo $this->Form->end('Submit');
    ?>

We now have a fully working authentication system. We can add new users by browsing to http://localhost/users/add, logging in by browsing to http://localhost/users/login, and finally logging out by browsing to http://localhost/users/logout.

After creating a user, you should see the login form with a success message, as shown in the following screenshot:

CakePHP 1.3 Application Development Cookbook

How it works…

We start by creating two actions in the UsersController class: login(), to show and process submissions of the login form, and logout(), to handle users logging out.

You may be surprised that the login() method has no logic whatsoever. To display the form, all we need to do is display the action’s view. The form submission is taken care of by the Auth component, leaving us with no need to implement any controller logic. Therefore, the only implementation we need is to create a view for this action, which includes a simple form with two fields: username, and password.

The inputs method of CakePHP’s FormHelper is a shortcut designed to avoid multiple calls to the input method. By using it, we can create a full form with elements without the need to call FormHelper::input() several times.

The logout() controller action simply calls the Auth component’s logout() method. This method removes the logged-in user data from the session, and returns the address to which the user should be redirected after logging out, obtained from the previously configured logoutRedirect setting of the component (defaults to the application’s home page if the setting was not configured.)

Next, we add two components to the controller: Session, and Auth. The Session component is needed to create the messages (through the use of its setflash() method) that informs the user if a login attempt was unsuccessful, or if a user was created.

The Auth component operates between your controller’s actions and the incoming request by means of the beforeFilter callback method. It uses it’s authorize setting to check what type of authentication scheme is to be used.

Once the Auth component is added to a controller, all actions in that controller are not accessible unless there is a valid user logged in. This means that if we had any actions that should be public (such as the login() and add() actions in our controller), we would have to tell the Auth component about them.

If one wishes to make some actions public, one can add the name of these actions to the allowedActions setting of the Auth component, or by calling its allow() method. We use the later approach to tell the Auth component that the add() action should be reachable without a logged-in user. The login() action is automatically added to the list of public actions by the Auth component.

When the user attempts to reach an action that is not within the public actions, the Auth component checks the session to see if a user is already logged in. If a valid user is not found, it redirects the browser to the login action. If there is a user who is logged in, it uses the controller’s isAuthorized method to check if the user has access. If its return value is true, it allows access, otherwise access is rejected. In our case, we implemented this method in AppController, our base controller class. If the attempted action requires a user who is logged in, the login() action is executed. After the user submits data using the login form, the component will first hash the password field, and then issue a find operation on the User model to find a valid account, using the posted username and password. If a valid record is found, it is saved to the session, marking the user as logged in.

Hashing a password confirmation field

When the Auth component is enabled on a controller and the user submits a form with a field named password (regardless if it is being rendered in the login form), the component will automatically hash the password field before executing the controller’s action.

The Auth component uses the salt defined in the configuration setting Security.salt (in your app/config/core.php file) to calculate the hash. Different salt values will produce different hashes even when using the same password. Therefore, make sure you change the salt on all your CakePHP applications, thus enhancing the security of your authentication system.

This means that the action will never hold the plain password value, and this should be particularly noted when utilizing mechanisms to confirm password validations. When you are implementing such validation, make sure you hash the confirmation field using the proper method:

if (!empty($this->data)) {
$this->data['User']['confirm_password'] = $this->Auth-
>password($this->data['User']['confirm_password']);
// Continue with processing
}

Using and configuring the Auth component

If there is something that defines the Auth component, it is its flexibility that accounts for different types of authentication modes, each of these modes serving different needs. In this recipe, you will learn how to modify the component’s default behavior, and how to choose between the different authentications modes.

Getting ready

We should have a fully working authentication system, so follow the entire recipe Setting up a basic authentication system.

We will also add support to have disabled user accounts. Add a field named active to your users table with the following SQL statement:

ALTER TABLE `users`
ADD COLUMN `active` TINYINT UNSIGNED NOT NULL default 1;

How to do it…

  1. Modify the definition of the Auth component in your AppController class, so it looks like the following:

    public $components = array(
    'Auth' => array(
    'authorize' => 'controller',
    'loginRedirect' => array(
    'admin' => false,
    'controller' => 'users',
    'action' => 'dashboard'
    ),
    'loginError' => 'Invalid account specified',
    'authError' => 'You don't have the right permission'
    ),
    'Session'
    );

  2. Now while still editing your app/app_controller.php file, place the following code right below the components property declaration, at the beginning of the beforeFilter method in your AppController class:

    public function beforeFilter() {
    if ($this->Auth->getModel()->hasField('active'))
    {$this->Auth->userScope = array('active' => 1);
    }
    }

  3. Copy the default layout from cake/libs/view/layouts/default.ctp to your app/views/layouts directory, and make sure you place the following line in your layout where you wish to display authentication messages:

    <?php echo $this->Session->flash('auth'); ?>

  4. Edit your app/controllers/users_controller.php file and place the following method right below the logout() method:
    public function dashboard() {
    }
  5. Finally, create the view for this newly added action in a file named dashboard.ctp and place it in your app/views/users folder with the following contents:
    <p>Welcome!</p>

If you now browse to http://localhost/users/login and enter the wrong credentials (wrong username and/or password), you should see the error message shown in the following screenshot:

CakePHP 1.3 Application Development Cookbook

How it works…

As the Auth component does its magic right before a controller action is executed, we either need to specify its settings in the beforeFilter callback, or pass them in an array when adding the component to the components property. A common place to do it is in the beforeFilter() method of the AppController class, as by doing so we can share the same authentication settings throughout all our controllers.

This recipe changes some Auth settings, so that whenever a valid user logs in, they are automatically taken to a dashboard action in the UsersController (done via the loginRedirect setting.) It also adds some default error messages through the component’s respective settings: loginError for when the given account is invalid, and authError for when there is a valid account, but the action is not authorized (which can be achieved by returning false from the isAuthorized() method implemented in AppController.)

It also sets the component’s userScope setting in AppController::beforeFilter(). This setting allows us to define which conditions the User find operation need to match to allow a user account to log in. By adding the userScope setting, we ensure that only user records that have the active field set to 1 are allowed access.

Changing the default user model

As you may have noticed, the role of the User model is crucial, not only to fetch the right user account, but also to check the permissions on some of the authentication schemes. By default, the Auth component will look for a User model, but you can change which model is to be used by setting the userModel property or the userModel key in the settings array.

For example, if your user model is Account, you would add the following setting when adding the Auth component to your controller:

'userModel' => 'Account'

Or equivalently, you would add the following to the beforeFilter method of your AppController class, in the block of code where you are setting up the component:

$this->Auth->userModel = 'Account';

There’s more…

The $authorize property of the Auth component (or the authorize key in the Auth component settings array) defines which authentication scheme should be used. Possible values are:

  • controller: It makes the component use the controller’s isAuthorized method, which returns true to allow access, or false to reject it. This method is particularly useful when obtaining the logged-in user
  • model: It is similar to controller; instead of using the controller to call the method, it looks for the isAuthorized method in the User model. First, it tries to map the controller’s action to a CRUD operation (one of ‘create‘, ‘read‘, ‘update‘, or ‘delete‘), and then calls the method with three arguments: the user record, the controller that is being accessed, and the CRUD operation (or actual controller action) that is to be executed.
  • object: It is similar to model; instead of using the model to call the method, it looks for the isAuthorized method in a given class. In order to specify which class, set the AuthComponent::$object property to an instance of such a class. It calls the method with three arguments: the user record, the controller that is being accessed, and the action that is to be executed.
  • actions: It uses the Acl component to check for access, which allows a much more grained access control.
  • crud: It is similar to actions; the difference lies in the fact that it first tries to map the controller’s action to a CRUD operation (one of ‘create‘, ‘read‘, ‘update‘, or ‘delete‘.)

 

LEAVE A REPLY

Please enter your comment!
Please enter your name here