Encodera

Thanks for reading!

Donate to the site — we work hard for you.

Contents

Authentication

Authentication is checking who the visitor is: the visitor enters an email and a password, and the site remembers them in the session. In CakePHP this is done by the official Authentication plugin. A plugin is a separate package that extends the framework.

Installation

composer require "cakephp/authentication:^3.0"
bin/cake plugin load Authentication

The first command downloads the package and the second one enables it in the project.

The users table

bin/cake bake migration CreateUsers email:string:unique password:string created modified
bin/cake migrations migrate
bin/cake bake all Users

The result is the users table, a model, UsersController and templates, including the registration form at /users/add.

Password hash

A password must not be stored as plain text. Add a method to the entity class that hashes it on every assignment:

// src/Model/Entity/User.php
use Authentication\PasswordHasher\DefaultPasswordHasher;
 
protected function _setPassword(string $password): ?string
{
    return $password !== '' ? (new DefaultPasswordHasher())->hash($password) : null;
}

A method with the _set prefix is called when the field is written. Register a user at /users/add and the database holds a long hash string.

Setup

The plugin is set up in src/Application.php. The class must implement an interface and get a new method:

// src/Application.php
use Authentication\AuthenticationService;
use Authentication\AuthenticationServiceInterface;
use Authentication\AuthenticationServiceProviderInterface;
use Authentication\Middleware\AuthenticationMiddleware;
use Psr\Http\Message\ServerRequestInterface;
 
class Application extends BaseApplication implements AuthenticationServiceProviderInterface
{
    public function getAuthenticationService(ServerRequestInterface $request): AuthenticationServiceInterface
    {
        $service = new AuthenticationService([
            'unauthenticatedRedirect' => '/users/login',
            'queryParam' => 'redirect',
        ]);
 
        $fields = ['username' => 'email', 'password' => 'password'];
 
        $service->loadAuthenticator('Authentication.Session');
        $service->loadAuthenticator('Authentication.Form', [
            'fields' => $fields,
            'loginUrl' => '/users/login',
        ]);
        $service->loadIdentifier('Authentication.Password', ['fields' => $fields]);
 
        return $service;
    }
}

Session recognises a user who is already logged in and Form checks the submitted login form. In the middleware() method of the same file add a line after RoutingMiddleware:

->add(new AuthenticationMiddleware($this))

And load the component in AppController::initialize():

$this->loadComponent('Authentication.Authentication');

From this moment all pages require login: a guest is redirected to /users/login.

Login and logout

// src/Controller/UsersController.php
public function beforeFilter(\Cake\Event\EventInterface $event): void
{
    parent::beforeFilter($event);
 
    $this->Authentication->allowUnauthenticated(['login', 'add']);
}
 
public function login()
{
    $result = $this->Authentication->getResult();
 
    if ($result && $result->isValid()) {
        return $this->redirect($this->Authentication->getLoginRedirect() ?? '/');
    }
 
    if ($this->request->is('post')) {
        $this->Flash->error('Wrong email or password.');
    }
}
 
public function logout()
{
    $this->Authentication->logout();
 
    return $this->redirect(['action' => 'login']);
}

The plugin checks the email and password itself; the action only looks at the result. allowUnauthenticated() opens the listed actions to guests.

The login form

Create templates/Users/login.php:

<h1>Log in</h1>
 
<?= $this->Form->create() ?>
<?= $this->Form->control('email', ['label' => 'Email']) ?>
<?= $this->Form->control('password', ['label' => 'Password']) ?>
<?= $this->Form->button('Log in') ?>
<?= $this->Form->end() ?>

Open /articles: you are redirected to the login form and returned back after logging in.

The current user

$user = $this->request->getAttribute('identity');
 
$userId = $user->getIdentifier();
$email = $user->email;

The identity attribute holds the logged-in user, or null for a guest.

Common mistake

After the plugin is enabled all pages become closed, including the login page itself. If it is not opened with allowUnauthenticated(['login']), a guest gets into an endless redirect. Public pages, such as the list and view of articles, are opened the same way in the beforeFilter() of their controller.

Thanks for reading!

Donate to the site — we work hard for you.