Authentication and Authorization with Quantum PHP Framework

Softberg Sb
5 min readJan 26, 2020

--

If you haven’t noticed yet the Auth feature was added into Quantum PHP framework from version 1.9, which includes all the aspects of authentication and authorization.

The philosophy behind the Auth library is to not rely only to the database but instead consider that user repository can be anything from regular file, database or even some online service working with its API and SDK etc.
This means also that you are not forced to use some kind of predefined table structure for users.

Of course you should somehow map your key fields to perform actions against and all this prepared for you to have complete Auth system on you website or app.

The version 1.9 comes with simple demo, that shows how you can perform sign up, sign in, etc. and see how smooth all that works. It includes also some article posting feature to demonstrate what authenticated users can do wile the guests does not.

By the way the Auth is specifically implemented for Web and API platforms keeping everything as simple as possible.

You need to have configuration file for auth (comes with the project), where you need to defined the type and the service.
The type can be `web` or `api` depending to you project. The service is just the service class which we will use a bit later.

Auth library uses strong crypto and hashing algorithms to make the feature secure and reliable. Check Security features of Quantum PHP Framework for more information.

The repository for the users, `files` are used for simplicity and to not make you create database, tables, etc. to see how it works.

The key role here plays the service AuthService which becomes the bridge between the controller and user repository and allows you to map the keys and field names to correspond to your repository.

In the AuthService (which should implement AuthServiceInterface interface) you need to implement several methods but you are free to implement the logic of getting, adding or updating the data the way you want.

In real world the files as a data storage is not quite compatible and that’s why we will implement the Auth on database today.

Preparing the database

Just create new database with table ` users` with the following structure:

CREATE TABLE `users` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`username` varchar(255) NOT NULL,
`password` varchar(255) NOT NULL,
`role` varchar(255) NOT NULL,
`firstname` varchar(255) NOT NULL,
`lastname` varchar(255) NOT NULL,
`activation_token` varchar(255) NOT NULL,
`remember_token` varchar(255) NOT NULL,
`reset_token` varchar(255) NOT NULL,
`refresh_token` varchar(255) NOT NULL,
`created_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

Make sure you have correct database details in your .env file.

Next we need to create our Auth model to interact with the database.

<?php namespace Base\models; use Quantum\Mvc\Qt_Model; class AuthModel extends Qt_Model 
{
public $table = 'users';
protected $fillable = [
'username',
'password',
'activation_token',
'firstname',
'lastname'
];
}

Updating the Auth Service

In project tree under base/ Services/ directory you can find AuthService class where we should apply our modifications. As mentioned before for demo purposes files were used for storing the data. So we will keep the method names but will overwrite the content to make it work with database.

<?php use Quantum\Libraries\Auth\AuthServiceInterface; 
use Quantum\Exceptions\ExceptionMessages;
use Quantum\Factory\ModelFactory;
use Quantum\Mvc\Qt_Service;
use Base\Models\AuthModel;
class AuthService extends Qt_Service implements AuthServiceInterface {
public function __init(ModelFactory $modelFactory)
{
$this->authModel = $modelFactory->get(AuthModel::class);
}
public function getVisibleFields()
{
return [
'username',
'firstname',
'lastname',
'role'
];
}
public function getDefinedKeys()
{
return [
'usernameKey' => 'username',
'passwordKey' => 'password',
'activationTokenKey' => 'activation_token',
'rememberTokenKey' => 'remember_token',
'resetTokenKey' => 'reset_token',
'accessTokenKey' => 'access_token',
'refreshTokenKey' => 'refresh_token'
];
}
public function get($field, $value) : array
{
return $this->authModel
->findOneBy($field, $value)
->asArray();
}
public function add($data)
{
$user = $this->authModel
->create()
->fillObjectProps($data)
->save();
return $user->asArray();
}
public function update($field, $value, $data)
{
$user = $this->authModel->findOneBy($field, $value);
foreach ($data as $key => $value) {
$user->$key = $value;
} $user->save();
}
}

In the code above, first we initialized our AuthModel model. in next 2 methods we have specified the visible fields and the key fields. The visible fields are the once which are kept with `user` object after sign in. The key fields are only for Auth library.

Next 3 methods as you guess is for getting, adding and updating user related properties.

Pay attention that you can write completely different code according to your needs. You may like to break the user table with multiple tables, etc. But that would require more advanced code so we will stick with one table for now…

You may not believe me, but you already have complete Auth feature for your project! (as the demo projects already comes with AuthController and middlewares).

So let’s just go through in what we already have…
Those are routes, middlewares and the controller AuthController.

Routes

We will consider the Web platform routes.

<?php return function ($route) { $route->group('guest', function ($route) {     $route->add('[:alpha:2]?/signin', 'GET|POST', 'AuthController', 'Signin');     $route->add('[:alpha:2]?/signup', 'GET|POST', 'AuthController', 'signup') ->middlewares(['Signup']);     $route->add('[:alpha:2]?/activate/[:any]', 'GET', 'AuthController', 'activate') ->middlewares(['Activate']);     $route->add('[:alpha:2]?/forget', 'GET|POST', 'AuthController', 'forget') ->middlewares(['Forget']);     $route->add('[:alpha:2]?/reset/[:any]', 'GET|POST', 'AuthController', 'reset')->middlewares(['Reset']); }) ->middlewares(['Guest']); $route->group('auth', function ($route) { 

$route->add('[:alpha:2]?/signout', 'GET', 'AuthController', 'signout'); })->middlewares(['Auth']);
};

As you can see there are 5 routes in guest group and one in auth group.

Notice that almost each route has middlware. You can go ahead and check each of them and made modifications if you need. Those are mainly validations that are perform against the data in request and then move forward to controller.

Controller

In the AuthController each methods are already defined according to the routes. You can check and modify each of them by yourself.. we will look only the signin here.

<?php public function signin(Request $request) 
{
if ($request->getMethod() == 'POST') {
try {
if (auth()->signin($request->get('email'), $request->get('password'), !!$request->get('remember'))) {
redirect(base_url() . '/' . current_lang());
}
} catch (AuthException $e) {
session()->setFlash('error', $e->getMessage());
redirect(base_url() . '/' . current_lang() . '/signin');
}
} else {
$this->view->render($this->signinView);
}
}

As you can see in order to access Auth library methods we using auth() helper facade. Same way we can access to other Auth methods via auth() helper method. For example if we want to print current logged in user first and last names in view, we will do it like this:

<div>
<?php
echo auth()->user()->firstname . ' ' . auth()->user()->lastname
?>
</div>

To get familiar with other Auth methods check the documentation.

Originally published at http://blog.softberg.org on January 26, 2020.

--

--