</> Code The Pixel

CakePHP 4 Authentication Using Authentication Plugin

Asyraf Wahi Anuar - May 11, 2020

Estimated reading time: 4 minutes, 28 seconds

This tutorial will guide you to create authentication for your CakePHP 4 project. The CakePHP Authentication plugin is used in this tutorial. This tutorial covers the basic authentication process (login, logout, hashing password). You'll need a composer installed on your computer to download the Authentication plugin.

Navigate your CLI to your application directory and execute the following command. Use the composer to install the Authentication Plugin:

composer require cakephp/authentication:^2.0


Adding Password Hashing at .../src/Model/Entity/User.php add the following:

<?php
namespace App\Model\Entity;

use Authentication\PasswordHasher\DefaultPasswordHasher; // Add this line
use Cake\ORM\Entity;

class User extends Entity
{
    // Others code.

    // Add this method
    protected function _setPassword(string $password) : ?string
    {
        if (strlen($password) > 0) {
            return (new DefaultPasswordHasher())->hash($password);
        }
    }
}


In .../src/Application.php, add the following imports and authentication interface on Application class (Attention: Do not redeclare the public function middleware(MiddlewareQueue $middlewareQueue): MiddlewareQueue) - The public function already exists and need some modification only:

use Authentication\AuthenticationService;
use Authentication\AuthenticationServiceInterface;
use Authentication\AuthenticationServiceProviderInterface;
use Authentication\Middleware\AuthenticationMiddleware;
use Psr\Http\Message\ServerRequestInterface;

use Cake\Core\Configure;
use Cake\Core\Exception\MissingPluginException;
use Cake\Error\Middleware\ErrorHandlerMiddleware;
use Cake\Http\BaseApplication;
use Cake\Http\MiddlewareQueue;
use Cake\Routing\Middleware\AssetMiddleware;
use Cake\Routing\Middleware\RoutingMiddleware;

class Application extends BaseApplication implements AuthenticationServiceProviderInterface //add this
{

	public function middleware(MiddlewareQueue $middlewareQueue): MiddlewareQueue
	{
		$middlewareQueue
			->add(new ErrorHandlerMiddleware(Configure::read('Error')))
            ->add(new AssetMiddleware([
                'cacheTime' => Configure::read('Asset.cacheTime'),
            ]))
			->add(new RoutingMiddleware($this))
			->add(new AuthenticationMiddleware($this));

		return $middlewareQueue;
	}
	
	public function getAuthenticationService(ServerRequestInterface $request): AuthenticationServiceInterface
	{
		$authenticationService = new AuthenticationService([
			'unauthenticatedRedirect' => \Cake\Routing\Router::url([
			'controller' => 'Users',
			'action' => 'login',
			'plugin' => null,
			'prefix' => null
			]),
			'queryParam' => 'redirect',
		]);

		// Load identifiers, ensure we check email and password fields
		$authenticationService->loadIdentifier('Authentication.Password', [
			'fields' => [
				'username' => 'username', //multifield: ['username', 'email']
				'password' => 'password',
			]
		]);

		// Load the authenticators, you want session first
		$authenticationService->loadAuthenticator('Authentication.Session');
		// Configure form data check to pick email and password
		$authenticationService->loadAuthenticator('Authentication.Form', [
			'fields' => [
				'username' => 'username',
				'password' => 'password',
			],
			'loginUrl' => \Cake\Routing\Router::url([
			'controller' => 'Users',
			'action' => 'login',
			'plugin' => null,
			'prefix' => null
			]),
		]);

		return $authenticationService;
	}


In .../src/Controller/AppController.php class add the following code:

public function initialize(): void
{
    parent::initialize();
    $this->loadComponent('RequestHandler');
    $this->loadComponent('Flash');

    // Add this line to check authentication result and lock your site
    $this->loadComponent('Authentication.Authentication');


In .../src/Controller/UsersController, add the following code:

public function beforeFilter(\Cake\Event\EventInterface $event)
{
    parent::beforeFilter($event);
    $this->Authentication->addUnauthenticatedActions(['login']);
}

public function login()
{
    $this->request->allowMethod(['get', 'post']);
    $result = $this->Authentication->getResult();
    if ($result->isValid()) {
        $redirect = $this->request->getQuery('redirect', [
            'controller' => 'Users',
            'action' => 'index',
        ]);

        return $this->redirect($redirect);
    }
    if ($this->request->is('post') && !$result->isValid()) {
        $this->Flash->error(__('Invalid username or password'));
    }
}

public function logout()
{
    $result = $this->Authentication->getResult();
    if ($result->isValid()) {
        $this->Authentication->logout();
        return $this->redirect(['controller' => 'Users', 'action' => 'login']);
    }
}


Create the template logic for login action:

<div class="users form">
    <?= $this->Flash->render() ?>
    <h3>Login</h3>
    <?= $this->Form->create() ?>
    <fieldset>
        <legend><?= __('Please enter your username and password') ?></legend>
        <?= $this->Form->control('email', ['required' => true]) ?>
        <?= $this->Form->control('password', ['required' => true]) ?>
    </fieldset>
    <?= $this->Form->submit(__('Login')); ?>
    <?= $this->Form->end() ?>

    <?= $this->Html->link("Add User", ['action' => 'add']) ?>
</div>


Navigate to localhost/myCake4/users and it will redirect you to the login page as follows:



To allow the add/register new user, navigate to usersController.php and modify the public function before filter. Allow the 'add' page to render without authentication.

public function beforeFilter(\Cake\Event\EventInterface $event)
{
    parent::beforeFilter($event);
    $this->Authentication->addUnauthenticatedActions(['login','add']);
}


Register a new user and log in using the created account. The password should be hashed and secure. Once logged in, it will redirect to the user index page as follows:



To generate the logout button on the index page, navigate to .../templates/User/index.php and add the following codes:

<?= $this->Html->link(__('Logout'), ['action' => 'logout'], ['class' => 'button float-right']) ?>


TIPS: Use password_verify to verify the password matches a hash. 

<?php
// Your password hash value
$hash = '$2y$10$MC84b2abTpj3TgHbpcTh2OYW5sb2j7YHg.Rj/DWiUBKYRJ5./NaRi';

if (password_verify('123456', $hash)) {
    echo 'Password is valid!';
} else {
    echo 'Invalid password.';
}
?>


View auth info helper:

public function initialize(): void
{
	$this->loadHelper('Authentication.Identity');
}


If you want to print the current authenticated username, use the following code:

<?php echo $this->Identity->get('username'); ?>


Logged in simple conditional check:

<?php
if ($this->Identity->isLoggedIn()) {
    echo 'User Logged in';
}
?>


To capture currently authenticated user ID in the controller, simply use the following code before save in the controller:

$article->user_id = $this->Authentication->getIdentity('id')->getIdentifier('id'); //capture auth id


That's all, happy coding :)


Cite this article (APA 6th Edition)

Popular
CakePHP 4 Print PDF Using CakePDF
June, 17 2020
CakePHP 4 jQuery Date Time Picker
October, 01 2018
CakePHP 4 Authentication Using Auth...
May, 14 2020
CakePHP 4 Export To CSV
May, 29 2020
CakePHP 4 Authentication Using...
May, 11 2020
CakePHP 4 File Upload Using Proffer Plugin
May, 15 2020
CakePHP 4 Find, Sort & Count
June, 02 2020
Share
Sharing Link
Click the icon to share