Cake offers a very good tutorial on using the Auth component here, but it’s not complete. Here’s what we’re going to build: A web application that uses CakePHP’s Auth component to login, logout, and access certain pages when the user is not authorized. After the user is logged in, they can go to the dashboard and edit the user.
Create Mysql Database and Table
In the first step we need to create a database and tables, so here I have created a database of tables “webscodex” and ”users” with identifiers and columns with names. You simply create a Users table as described in the SQL query.
Let’s start by creating a user database table. The user table contains email, password. Additional fields are meta field fields such as created and updated fields. Here is what the final users table looks like.
-- Database: `webscodex` -- Table structure for table `users` CREATE TABLE `users` ( `id` int(100) NOT NULL PRIMARY KEY AUTO_INCREAMENT, `name` varchar(100) NOT NULL, `email` varchar(100) NOT NULL, `username` varchar(100) NOT NULL, `password` varchar(100) NOT NULL, `created` datetime NOT NULL, `updated` datetime NOT NULL ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
Routes
Now let’s modify CakePHP’s main component to support our login module. First we need to change routes.php so we can have a custom login, logout and dashboard. This step is optional, but I’ll do it to keep the URL looking clean.
config/routes.php
<?php use Cake\Routing\Route\DashedRoute; use Cake\Routing\RouteBuilder; $routes->setRouteClass(DashedRoute::class); $routes->scope('/', function (RouteBuilder $builder) { $builder->connect('/', ['controller' => 'Users', 'action' => 'login']); $builder->fallbacks(); });
Installing Authentication Plugin
Go to project directory and run this command on your command prompt.
composer require cakephp/authentication:^2.0
Adding Password Hashing
src/Model/Entity/User.php
<?php namespace App\Model\Entity; use Authentication\PasswordHasher\DefaultPasswordHasher; use Cake\ORM\Entity; class User extends Entity { protected $_accessible = [ '*' => true, 'id' => false ]; protected function _setPassword(string $password) : ?string { if (strlen($password) > 0) { return (new DefaultPasswordHasher())->hash($password); } } }
Adding Login
In src/Application.php, add the following imports:
// In src/Application.php add the following imports use Authentication\AuthenticationService; use Authentication\AuthenticationServiceInterface; use Authentication\AuthenticationServiceProviderInterface; use Authentication\Middleware\AuthenticationMiddleware; use Psr\Http\Message\ServerRequestInterface;
Then implement the authentication interface on your Application class:
// in src/Application.php class Application extends BaseApplication implements AuthenticationServiceProviderInterface {
Then add the following:
src/Application.php
public function middleware(MiddlewareQueue $middlewareQueue): MiddlewareQueue { $middlewareQueue ->add(new ErrorHandlerMiddleware(Configure::read('Error'))) ->add(new RoutingMiddleware($this)) ->add(new AssetMiddleware([ 'cacheTime' => Configure::read('Asset.cacheTime'), ])) ->add(new RoutingMiddleware($this)) ->add(new AuthenticationMiddleware($this)) ->add(new BodyParserMiddleware()) ->add(new CsrfProtectionMiddleware([ 'httponly' => true, ])); return $middlewareQueue; } public function getAuthenticationService(ServerRequestInterface $request): AuthenticationServiceInterface { $authenticationService = new AuthenticationService([ 'unauthenticatedRedirect' => Router::url(['controller'=> 'Users', 'action'=> 'login']), ]); // Load identifiers, ensure we check email and password fields $authenticationService->loadIdentifier('Authentication.Password', [ 'fields' => [ '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' => 'email', 'password' => 'password', ], 'loginUrl' => Router::url(['controller'=> 'Users', 'action'=> 'login']), ]); return $authenticationService; }
In your AppController class add the following code
src/Controller/AppController.php
<?php // src/Controller/AppController.php declare(strict_types=1); namespace App\Controller; use Cake\Controller\Controller; class AppController extends Controller { public function initialize(): void { parent::initialize(); $this->loadComponent('RequestHandler'); $this->loadComponent('Flash'); $this->loadComponent('FormProtection'); $this->loadComponent('Authentication.Authentication'); } }
In your UsersController, add the following code
src/Controller/UsersController.php
<?php // in src/Controller/UsersController.php namespace App\Controller; use App\Controller\AppController; use Cake\Event\EventInterface; use Cake\Datasource\FactoryLocator; class UsersController extends AppController{ public $usersTableObj; public function beforefilter(EventInterface $event){ parent::beforefilter($event); $this->usersTableObj = FactoryLocator::get('Table')->get('Users'); $this->Authentication->addUnauthenticatedActions(['login', 'add']); } public function index(){ $this->loadComponent('Paginator'); $users = $this->Paginator->paginate($this->usersTableObj->find()); $this->set(compact('users')); } public function login(){ $data = $this->request->allowMethod(['get', 'post']); $result = $this->Authentication->getResult(); // regardless of POST or GET, redirect if user is logged in if ($result->isValid()) { return $this->redirect(['controller'=>'Posts', 'action'=>'index']); } // display error if user submitted and authentication failed if ($this->request->is('post') && !$result->isValid()) { $this->Flash->error(__('Invalid Email or Password')); } } public function logout(){ $result = $this->Authentication->getResult(); // regardless of POST or GET, redirect if user is logged in if ($result->isValid()) { $this->Authentication->logout(); return $this->redirect(['controller' => 'Users', 'action' => 'login']); } } public function add(){ $userEnt = $this->usersTableObj->newEmptyEntity(); if ($this->request->is('post')) { $userPost = $this->request->getData(); $users = $this->usersTableObj->patchEntity($userEnt, $userPost); if ($this->usersTableObj->save($userEnt)) { $this->Flash->success(__('Your user has been saved.')); return $this->redirect(['controller'=>'Users','action' => 'index']); }else{ $this->Flash->error(__('Unable to add your user.')); return $this->redirect(['controller'=>'Users','action' => 'add']); } } $this->set(compact('userEnt', $userEnt)); } public function edit($id=null){ $userEnt = $this->usersTableObj->get($id); if ($this->request->is(['post', 'put'])) { $editPost = $this->request->getData(); $editUser = $this->usersTableObj->patchEntity($userEnt, $editPost); if ($this->usersTableObj->save($userEnt)) { $this->Flash->success(__('Your user has been updated.')); return $this->redirect(['controller'=>'Users','action' => 'index']); }else{ $this->Flash->error(__('Unable to update your user.')); return $this->redirect(['controller'=>'Users','action' => 'add']); } } $this->set(compact('userEnt', $userEnt)); } public function delete($id=null){ $userEnt = $this->usersTableObj->get($id); if ($this->usersTableObj->delete($userEnt)) { $this->Flash->success(__('User has been deleted.')); return $this->redirect(['controller'=>'Users','action' => 'index']); }else{ $this->Flash->error(__('Unable to delete your user.')); return $this->redirect(['controller'=>'Users','action' => 'index']); } } }
Add the template for your add, edit and login action:
In /templates/Users/add.php
<div class="text-center" style="margin-top: 50px;"> <h4>User Registration Form</h4> </div> <div class="container"> <div class="row"> <div class="col-sm-3"></div> <div class="col-sm-6"> <?php echo $this->Form->create($userEnt, ['name'=>'add_users', 'class'=>'was-validated']) ?> <div class="form-group"> <?php echo $this->Form->control('name', ['type'=>'text', 'class'=>'form-control','placeholder'=>'Enter name','required'=>true]);?> </div> <div class="form-group"> <?php echo $this->Form->control('email', ['type'=>'email', 'class'=>'form-control','placeholder'=>'Enter email','required'=>true]);?> </div> <div class="form-group"> <?php echo $this->Form->control('username', ['type'=>'text', 'class'=>'form-control','placeholder'=>'Enter username','required'=>true]);?> </div> <div class="form-group"> <?php echo $this->Form->control('password', ['type'=>'password', 'class'=>'form-control','placeholder'=>'Enter password','required'=>true]);?> </div> <button type="submit" class="btn btn-primary" style="float: right;">Sign Up</button> <?php echo $this->Form->end() ?> </div> </div> </div>
Output

In /templates/Users/index.php
<div class="container"> <div class="row"> <div class="col-md-12"> <h2 class="text-center" style="margin-top:50px;">Users View</h2> <table class="table"> <thead> <tr> <th>Id</th> <th>Name</th> <th>Username</th> <th>Email</th> <th>Created</th> <th>Updated</th> <th>Action</th> </tr> </thead> <tbody> <?php foreach ($users as $user) { ?> <tr> <td><?php echo $user->id ?></td> <td><?php echo $user->name ?></td> <td><?php echo $user->username ?></td> <td><?php echo $user->email ?></td> <td><?php echo date('d-M-Y', strtotime($user->created)) ?></td> <td><?php echo date('d-M-Y', strtotime($user->updated)) ?></td> <td> <a href="<?php echo $this->Url->build(['controller'=>'Users', 'action'=>'edit', $user->id]) ?>">Edit</a> <a href="<?php echo $this->Url->build(['controller'=>'Users', 'action'=>'delete', $user->id]) ?>" onclick="return confirm('Are you sure you want to delete this item?');">Delete</a> </td> </tr> <?php } ?> </tbody> </table> </div> </div> </div>
In /templates/Users/edit.php
<div class="text-center" style="margin-top: 50px;"> <h4>Edit User in Database using CakePHP 4</h4> </div> <div class="container"> <div class="row"> <div class="col-sm-3"></div> <div class="col-sm-6"> <?php echo $this->Form->create($userEnt, ['name'=>'edit_users', 'class'=>'was-validated']) ?> <div class="form-group"> <?php echo $this->Form->control('name', ['type'=>'text', 'class'=>'form-control','placeholder'=>'Enter name','required'=>true]);?> </div> <div class="form-group"> <?php echo $this->Form->control('email', ['type'=>'email', 'class'=>'form-control','placeholder'=>'Enter email','required'=>true]);?> </div> <div class="form-group"> <?php echo $this->Form->control('username', ['type'=>'text', 'class'=>'form-control','placeholder'=>'Enter username','required'=>true]);?> </div> <div class="form-group"> <?php echo $this->Form->control('password', ['type'=>'password', 'class'=>'form-control','placeholder'=>'Enter password','required'=>true]);?> </div> <button type="submit" class="btn btn-success" style="float: right;">Update</button> <?php echo $this->Form->end() ?> </div> </div> </div>
In /templates/Users/login.php
<div class="text-center" style="margin-top: 50px;"> <h4>User Login</h4> </div> <div class="container"> <div class="row"> <div class="col-sm-3"></div> <div class="col-sm-6"> <?php echo $this->Form->create(null, ['class'=>'was-validated']) ?> <div class="form-group"> <?php echo $this->Form->control('email', ['type'=>'email', 'class'=>'form-control','placeholder'=>'Enter Email','required'=>true]);?> </div> <div class="form-group"> <?php echo $this->Form->control('password', ['type'=>'password', 'class'=>'form-control','placeholder'=>'Enter Password','required'=>true]);?> </div> <button type="submit" class="btn btn-primary" style="float: right;">Login</button> <?php echo $this->Form->end() ?> </div> </div> </div>
Output

In your AppView
src/View/AppView.php
$this->loadHelper('Authentication.Identity');
For very simple checking whether the user is logged in you can use:
if ($this->Identity->isLoggedIn()) { ... }
Getting user data can be done with:
$username = $this->Identity->get('username');
You can always support by sharing on social media or recommending my blog to your friends and colleagues. If you have any suggestions or problems about this tutorial, please comment on the form below.😊
Good tutorial, I want a tutorial on authentication for an API in AJAX
thanks for your comment. yes sure, I will give you tutorial on this topic.