CakePHP3: User Authentication

Create users controller to manage, you guess it! users. Login, logout, signup, forgot password, change password, change email, update profile etc

add this line

namespace App\Model\Entity;

use Cake\ORM\Entity;
use Cake\Auth\DefaultPasswordHasher;

and add this method to the class

protected function _setPassword($value)
{
    $hasher = new DefaultPasswordHasher();
    return $hasher->hash($value);
}

Add some groups:

http://example.com/groups/add
  1. Admin
  2. Manager
  3. User

Now add some users, one for each groups

http://example.com/users/add

load the auth component, checking username and password field.

put it on initialize method

$this->loadComponent('Auth', [
        		'authenticate' => [
        				'Form' => [
        						'fields' => [
        								'username' => 'email',
        								'password' => 'password'
        						]
        				]
        		],
        		'loginAction' => [
        				'controller' => 'Users',
        				'action' => 'login'
        		],
        		'unauthorizedRedirect' => $this->referer() // If unauthorized, return them to page they were just on
        ]);

All page now can’t be accessed unless you are logged in. Add this below the code above so we can still visit homepage and other /pages/*

$this->Auth->allow(['display']);

I want users to be logged in for 30 days unless they logout

Update /config/app.php from

'Session' => [
        'defaults' => 'php',
    ],

to

'Session' => [
        'defaults' => 'php',
		'timeout' => 60*60*24*30,
		'ini' => [
				'session.cookie_lifetime' => 60*60*24*30
		]
    ],

add this login method to UsersController.php

It will redirect user to default login redirect url if logged in user is detected. Will also update last_login field

public function login()
	{
		//user already logged in? take to default login redirect
		if($this->Auth->user('id'))
			return $this->redirect($this->Auth->redirectUrl());
		
		if ($this->request->is('post')) {
			$user = $this->Auth->identify();

			if ($user) {
				$this->Auth->setUser($user);
				
				//update last login
				$user = $this->Users->get($user['id']);
				$user->last_login = date("Y-m-d H:i:s");
				$this->Users->save($user);
				
				return $this->redirect($this->Auth->redirectUrl());
			}
			$this->Flash->error('Your username or password is incorrect. Or account expired.');
		}
	}

and create the login form

<h1>Access Your Account</h1>
<?= $this->Form->create() ?>
    <fieldset>
        <legend><?= __('Access Your Account') ?></legend>
        <?php
            echo $this->Form->input('email');
            echo $this->Form->input('password');
        ?>
    </fieldset>
    <?= $this->Form->button(__('Login')) ?>
    <?= $this->Form->end() ?>
    
    <div class="columns">
	<?php echo $this->Html->link(__("Forgot You Password?"),['action'=>'forgotPassword']);?>
	</div>

On UsersController.php add initialize method. $this->Auth->allow() used to tell cakephp which method are accessible to public, everyone can access them without having to login.

Add some public method you will add later that you can think of right now to save time.

public function initialize()
{
	parent::initialize();
	$this->Auth->allow(['logout','signup','forgotPassword','resetPassword','profile']);
}

create logout method, no need to create a view file for this

public function logout()
{
	$this->Flash->success('See You Soon!');
	return $this->redirect($this->Auth->logout());
}

deny all access, except those set by controller $this->Auth->allow()

public function isAuthorized($user)
{
    return false;
}

add this line

$this->loadComponent('Auth', [
        		'authorize' => 'Controller',
        		'authenticate' => [
        				'Form' => [
        						'fields' => [
        								'username' => 'email',
        								'password' => 'password'
        						]
        				]
        		],
        		'loginAction' => [
        				'controller' => 'Users',
        				'action' => 'login'
        		],
        		'unauthorizedRedirect' => $this->referer() // If unauthorized, return them to page they were just on
        ]);

You should add this to each of controller you have

Now give user some access

index, changePassword, ChangeEmail, updateProfile method. We don’t need some condition for those, give them access (line 5-7)

Some other methods, something like /users/edit/1 or /users/view/1 we need to check and compare it current user and decide if user has access to it (line 12-16)

public function isAuthorized($user)
	{
		$action = $this->request->params['action'];
	
		if (in_array($action, ['index', 'changePassword', 'changeEmail', 'updateProfile'])) {
			return true;
		}

		if (empty($this->request->params['pass'][0])) {
			return false;
		}
	
		$id = $this->request->params['pass'][0];
		$usr = $this->Users->get($id);
		if ($usr->id == $user['id']) {
			return true;
		}
		return parent::isAuthorized($user);
	}

I also want users who login meets this condition:

expire field > now and active = ‘yes’

the code below tell auth component to use findAuth method to check if user is authorized

$this->loadComponent('Auth', [
        		'authorize' => 'Controller',
        		'authenticate' => [
        				'Form' => [
        						'fields' => [
        								'username' => 'email',
        								'password' => 'password'
        						],
        						'finder' => 'auth'
        				]
        		],
        		'loginAction' => [
        				'controller' => 'Users',
        				'action' => 'login'
        		],
        		'unauthorizedRedirect' => $this->referer() // If unauthorized, return them to page they were just on
        ]);

here’s the findAuth method

public function findAuth(\Cake\ORM\Query $query, array $options)
    {
    	$query
    	//->select(['id', 'username', 'password'])
    	->where(
    			[
    					'Users.expire >=' => date("Y-m-d H:i:s"),
    					'Users.active' => 'yes'
    			]
    		);
    
    	return $query;
    }

By the way, I’m going to use the exception

namespace App\Controller;

use App\Controller\AppController;
use Cake\Core\Exception\Exception;
public function validationChangePassword(Validator $validator) {
    	$validator
    		->add('old_password','custom',[
    			'rule' => function($value, $context) {
    				$user = $this->get($context['data']['id']);
    				if($user) {
    					if((new DefaultPasswordHasher)-&gt;check($value,$user-&gt;password)) <a style="color:#000;text-decoration:none" href="http://cococheats.com/episode-choose-your-story-hack/">episode passes</a>  {
    						return true;
    					}
    				}
    			},
    			'message' =&gt; 'The old password does not match the current password!'
    		])
    		-&gt;notEmpty('old_password');
    
    	$validator
    		-&gt;add('new_password',[
    			'length' =&gt; [
    				'rule' =&gt; ['minLength', 8],
    				'message' =&gt; 'The password have to be at least 8 characters!'
    			]
    		])
    		-&gt;add('new_password',[
    			'match' =&gt; [
    				'rule' =&gt; ['compareWith','confirm_password'],
    				'message' =&gt; 'The passwords does not match!'
    			]
    		])
    		-&gt;notEmpty('new_password');
    		
    	$validator
    		-&gt;add('confirm_password',[
    			'length' =&gt; [
    				'rule' =&gt; ['minLength', 8],
    				'message' =&gt; 'The password have to be at least 8 characters!'
    			]
    		])
    		-&gt;add('confirm_password',[
    			'match' =&gt; [
    				'rule' =&gt; ['compareWith','new_password'],
    				'message' =&gt; 'The passwords does not match!'
    			]
    		])
    		-&gt;notEmpty('confirm_password');

    	return $validator;
    }
    
	public function validationResetPassword(Validator $validator) {
    	$validator
    		-&gt;add('new_password',[
    			'length' =&gt; [
    				'rule' =&gt; ['minLength', 8],
    				'message' =&gt; 'The password have to be at least 8 characters!'
    			]
    		])
    		-&gt;add('new_password',[
    			'match' =&gt; [
    				'rule' =&gt; ['compareWith','confirm_password'],
    				'message' =&gt; 'The passwords does not match!'
    			]
    		])
    		-&gt;notEmpty('new_password');
    		
    	$validator
    		-&gt;add('confirm_password',[
    			'length' =&gt; [
    				'rule' =&gt; ['minLength', 8],
    				'message' =&gt; 'The password have to be at least 8 characters!'
    			]
    		])
    		-&gt;add('confirm_password',[
    			'match' =&gt; [
    				'rule' =&gt; ['compareWith','new_password'],
    				'message' =&gt; 'The passwords does not match!'
    			]
    		])
    		-&gt;notEmpty('confirm_password');

    	return $validator;
    }
    
    public function validationSignup(Validator $validator)
    {
    	$validator
    	-&gt;integer('id')
    	-&gt;allowEmpty('id', 'create');
    
    	$validator
    	-&gt;requirePresence('username', 'create')
    	-&gt;notEmpty('username')
    	-&gt;add('username', 'unique', ['rule' =&gt; 'validateUnique', 'provider' =&gt; 'table']);
    
    	$validator
    	-&gt;requirePresence('password', 'create')
    	-&gt;notEmpty('password');
    
    	$validator
    	-&gt;email('email')
    	-&gt;requirePresence('email', 'create')
    	-&gt;notEmpty('email');
    
    	$validator
    	-&gt;requirePresence('first_name', 'create')
    	-&gt;notEmpty('first_name');
    
    	$validator
    	-&gt;requirePresence('last_name', 'create')
    	-&gt;notEmpty('last_name');
    
    	return $validator;
    }

VN:F [1.9.20_1166]
Rating: 0.0/10 (0 votes cast)

Share and Enjoy

  • Facebook
  • Twitter
  • Delicious
  • LinkedIn
  • StumbleUpon
  • Add to favorites
  • Email
  • RSS