Skip to main content
deleted 16 characters in body
Source Link
Jamal
  • 35.2k
  • 13
  • 134
  • 238

I'm creating an authentication with the Slim 3 framework and PHP-DI 5 (PHP-DI/PHP-DIPHP-DI/PHP-DI).

The project will be the base/starter template for my new projects. I want it to be easy to extend, also to larger projects later on. So iI find it important that itsit's a really good structured project. AtmAt the moment, I'm trying to learn all the best practices of structuring projects. So, so all tips are welcome!

  1. Would you structure the User-model, Account-controller and Auth-class differently? Or do iI have a good base here?
  2. Am iI using dependency injection as how iI should use it? Is there a better way?
  3. Do the container items only get instantiated when itsit's called or is this a performance hit? Should iI implement this differently or is this correct?
  4. Would you prefer to place the isActivated()isActivated() and verifyPassword()verifyPassword() methods from the User-model in the Auth-class? Or is it at the right place there?

The code


 My container definitions

I'm creating an authentication with the Slim 3 framework and PHP-DI 5 (PHP-DI/PHP-DI).

The project will be the base/starter template for my new projects. I want it to be easy to extend, also to larger projects later on. So i find it important that its a really good structured project. Atm, I'm trying to learn all the best practices of structuring projects. So all tips are welcome!

  1. Would you structure the User-model, Account-controller and Auth-class differently? Or do i have a good base here?
  2. Am i using dependency injection as how i should use it? Is there a better way?
  3. Do the container items only get instantiated when its called or is this a performance hit? Should i implement this differently or is this correct?
  4. Would you prefer to place the isActivated() and verifyPassword() methods from the User-model in the Auth-class? Or is it at the right place there?

The code


 My container definitions

I'm creating an authentication with the Slim 3 framework and PHP-DI 5 (PHP-DI/PHP-DI).

The project will be the base/starter template for my new projects. I want it to be easy to extend, also to larger projects later on. So I find it important that it's a really good structured project. At the moment, I'm trying to learn all the best practices of structuring projects, so all tips are welcome!

  1. Would you structure the User-model, Account-controller and Auth-class differently? Or do I have a good base here?
  2. Am I using dependency injection as how I should use it? Is there a better way?
  3. Do the container items only get instantiated when it's called or is this a performance hit? Should I implement this differently or is this correct?
  4. Would you prefer to place the isActivated() and verifyPassword() methods from the User-model in the Auth-class? Or is it at the right place there?

My container definitions

edited title
Link
Ramon Bakker
  • 225
  • 1
  • 3
  • 10

Creating authentication MVC Auth Structure and Dependency Injection with PHP-DI 5 and Slim 3

Source Link
Ramon Bakker
  • 225
  • 1
  • 3
  • 10

Creating authentication with PHP-DI 5 and Slim 3

I'm creating an authentication with the Slim 3 framework and PHP-DI 5 (PHP-DI/PHP-DI).

The project will be the base/starter template for my new projects. I want it to be easy to extend, also to larger projects later on. So i find it important that its a really good structured project. Atm, I'm trying to learn all the best practices of structuring projects. So all tips are welcome!

My questions are:

  1. Would you structure the User-model, Account-controller and Auth-class differently? Or do i have a good base here?
  2. Am i using dependency injection as how i should use it? Is there a better way?
  3. Do the container items only get instantiated when its called or is this a performance hit? Should i implement this differently or is this correct?
  4. Would you prefer to place the isActivated() and verifyPassword() methods from the User-model in the Auth-class? Or is it at the right place there?

The code


My container definitions

<?php

use Slimproject\Models\User;
use Slimproject\Auth\Auth;

return [
    User::class => function (ContainerInterface $c) {
        return new User;
    },
    Auth::class => function (ContainerInterface $c) {
        return new Auth($c->get(User::class));
    }
];

The router

<?php

use Slimproject\Middleware\GuestMiddleware;
use Slimproject\Middleware\AuthMiddleware;

$app->get('/', ['Slimproject\Controllers\HomeController', 'index'])->setName('home');

$app->group('/account', function() {
    $this->get('/login', ['Slimproject\Controllers\AccountController', 'login'])->setName('account.login');
    $this->post('/login', ['Slimproject\Controllers\AccountController', 'doLogin'])->setName('account.login');
    // etc..
})->add(new GuestMiddleware($container));

$app->group('/myaccount', function() {
    $this->get('/', ['Slimproject\Controllers\MyAccountController', 'index'])->setName('myaccount.index');
    // etc..
})->add(new AuthMiddleware($container));

The Account-controller

<?php

namespace Slimproject\Controllers;

use Slim\Views\Twig;
use Psr\Http\Message\ResponseInterface as Response;
use Psr\Http\Message\ServerRequestInterface as Request;
use Slimproject\Auth\Auth;
use Slimproject\Models\User;

class AccountController
{
    public function doLogin(Request $request, Response $response, Twig $view, Auth $auth, User $user)
    {
        
        $user = $user->get($request->getParam('username'));
        
        if (!$user->isActivated() {
            $this->flash->addMessage('error', 'Your account is not yet activated.');
            return $view->render($response, 'account/login.twig');
        }
        
        if (!$user->verifyPassword($request->getParam('password')) {
            $this->flash->addMessage('error', 'Login incorrect.');
            return $view->render($response, 'account/login.twig');
        }
        
        $auth->login($user);
        
        
        return $view->render($response, 'myaccount/index.twig');
    }
}

The User-model

<?php

namespace Slimproject\Models;

use Illuminate\Database\Eloquent\Model;

class User extends Model
{
    protected $fillable = [
        'name',
        'username',
        'email',
        'password',
        'level',
        'activated'
    ];

    public function get($username) 
    {
        return $this->where('email', $username)->orWhere('username', $username)->first() ?: false;
    }

    public function isActivated()
    {
        return (bool) $this->activated;
    }

    public function verifyPassword($password)
    {
       return password_verify($password, $this->password);
    }
}

The Auth-middleware

<?php

namespace Slimproject\Middleware;

class AuthMiddleware extends Middleware
{
    public function __invoke($request, $response, $next)
    {
        if (!$this->auth->isLoggedIn()) {
            $this->flash->addMessage('error', 'You need to be logged in to visit that page.');
            return $response->withRedirect($this->router->pathFor('account.login'));
        }

        $response = $next($request, $response);
        return $response;
    }
}

The Auth-class

<?php

namespace Slimproject\Auth;

use Slimproject\Models\User;

class Auth
{
    protected $user;

    public function __construct(User $user)
    {
        $this->user = $user;
    }

    public function user()
    {
        return $this->user->where('id', $_SESSION['user']['id'])->first();
    }

    public function isLoggedin()
    {
        return isset($_SESSION['user']);
    }

    public function hasAccess(array $levels)
    {
        return in_array($_SESSION['user']['level'], $levels);
    }

    public function login(User $user)
    {
        $_SESSION['user'] = [
            'id' => $user->id,
            'username' => $user->username,
            'email' => $user->email,
            'level' => $user->level,
            'loggedin_at' => time(),
        ];
    }

    public function logout()
    {
        unset($_SESSION['user']);
    }
}