Authentication

Authentication Flow

Authenticate using an account type

For this purpose we’ve created the Prest\Auth\Manager which will store the session information for the duration of the request:

use Acme\Auth\AccountType\Username;

// Authenticate user using username and password (Username Account):
$session = $authManager->loginWithUsernamePassword(
    UsernameAccountType::NAME,
    $username,
    $password
);

On failure it will throw Prest\Exception\AuthException with Prest\Constants\ErrorCodes::AUTH_LOGIN_FAILED error code.

Receive session

After we’ve successfully authenticated we retrieve the Prest\Auth\Session which we then use to create a response.

/** @var \Prest\Auth\Session $session */
$session = $this->authManager->getSession();

$response = [
    'token'   => $session->getToken(),
    'expires' => $session->getExpirationTime(),
];

Store session

Because REST applications are supposed to be stateless, the session needs to be stored on the client.

Make subsequent request using the stored session

We can now authenticate any further requests using the received token from the initial authentication.

The Prest\Auth\Manager::authenticateToken will throw a new Prest\Exception\AuthException with following status codes:

Code Constant HTTP Status Code Message Reason
2030 AUTH_TOKEN_INVALID 401 Authentication: Token Invalid An invalid token has been given.
2040 AUTH_SESSION_EXPIRED 401 Authentication: Session Expired The session token has been expired.
2050 AUTH_SESSION_INVALID 401 Authentication: Session Invalid Failed to authenticate with use of provided identity.
/**
 * @var \Prest\Http\Request $request
 * @var \Prest\Auth\Manager $authManager
 */
if ($token = $this->request->getToken()) {
    $this->authManager->authenticateToken($token);
}

We’ve already incorporated the logic above in it’s own piece of middleware. Read more on our middleware.

Configure AuthManager

namespace Acme\Provider\AuthManager;

use Acme\Auth\Manager;
use Phalcon\DiInterface;
use Acme\Auth\AccountType\Username;
use Phalcon\Di\ServiceProviderInterface;

class ServiceProvider implements ServiceProviderInterface
{
    public function register(DiInterface $container)
    {
        $container->setShared(
            'authManager',
            function () {
                $config = $this->get('config');
                $manager = new Manager($config->path('auth.expiration'));
                $manager->registerAccountType(Username::NAME, new Username());

                return $manager;
            }
        );
    }
}

Add account types

Different account types may be added by creating a class that implements Prest\Auth\AccountType. This interface requires you to provide a login and an authenticate method.

For example Acme\Auth\AccountType\Username class:

namespace Acme\Auth\AccountType;

use Phalcon\Di;
use Phalcon\Security;
use Prest\Auth\Manager;
use Acme\Model\UserModel;
use Prest\Auth\AccountType;

class Username implements AccountType
{
    const NAME = 'username';

    public function login($data)
    {
        /** @var \Phalcon\Security $security */
        $security = Di::getDefault()->get(Services::SECURITY);

        $username = $data[Manager::LOGIN_DATA_USERNAME];
        $password = $data[Manager::LOGIN_DATA_PASSWORD];

        /** @var User $user */
        $user = User::findFirst([
            'conditions' => 'username = :username:',
            'bind'       => ['username' => $username],
        ]);

        if (!$user) {
            return null;
        }

        if (!$security->checkHash($password, $user->password)) {
            return null;
        }

        return (string)$user->id;
    }

    public function authenticate($id): bool
    {
        return User::count(['conditions' => 'id = :id:', 'bind' => ['id' => $id]]) > 0;
    }

Middleware

The middleware can be instantiated as follows:

use Prest\Middleware\AuthenticationMiddleware;

$eventsManager->attach('micro', AuthenticationMiddleware::class);

results matching ""

    No results matching ""