meun5
meun5

Reputation: 322

Slim 3 Implement Route Filtering

I am currently trying to implement route authentication filtering in Slim 3. What I would like to do is:

$app->get("/route", Filter::$guest(), function ($request, $response, $args) {
... 
});

or maybe

$app->get("/route", function ($resquest, $response, $args) {

})->add(Filter::Admin);

and the Filter class would be:

class Filter
{
    public static admin()
    {
        // Check if user is an admin.
        // If not, throw an Error
    }

...

In Slim 2, I could use someting like this

Filter.php

$authenticationCheck = function ($required) use ($app) {
    return function () use ($required, $app) {
        if ((!$app->auth && $required) || ($app->auth && !$required)) {
            $app->redirect($app->urlFor("home"));
        }
    };
};

$authenticated = function () use ($authenticationCheck) {
    return $authenticationCheck(true);
};

$guest = function () use ($authenticationCheck) {
    return $authenticationCheck(false);
};

$admin = function () use ($app) {
    return function () use ($app) {
        if (!$app->auth || !$app->auth->isAdmin()) {
            $app->notFound();
        }
    };
};

and in routes I could do:

$app->get("/route", $guest(), function () use ($app) {
    //Route
});

I know that I can get the route through middleware, but I can't think of a good way to diffrenciate between a "admin" route and a normal route without having to build some sort of list.

Upvotes: 1

Views: 2273

Answers (1)

Davide Pastore
Davide Pastore

Reputation: 8738

You could create a basic middleware class Authorization:

<?php
class Authorization
{
    /**
     * Authorization middleware invokable class
     *
     * @param  \Psr\Http\Message\ServerRequestInterface $request  PSR7 request
     * @param  \Psr\Http\Message\ResponseInterface      $response PSR7 response
     * @param  callable                                 $next     Next middleware
     *
     * @return \Psr\Http\Message\ResponseInterface
     */
    public function __invoke($request, $response, $next)
    {
        $user = ""; //It should come from some place :)
        if(!$this->isAuthorized($user)){
          return $response->withRedirect('/notAuthorized');
        }
        return $next($request, $response);
    }

    /**
     * Check if the given user is authorized.
     *
     * @param  string $user The user to check.
     *
     * @return boolean True if the user is authorized, false otherwise.
     */
    protected function isAuthorized($user){
      return false;
    }
}

Then you can extend it and create one middleware for guest authorization and another one for admin authorization:

<?php
class GuestAuthorization extends Authorization
{
  protected function isAuthorized($user){
    //Are you a guest?
    $isGuest = true; //Your magic business here
    return $isGuest;
  }
}

class AdminAuthorization extends Authorization
{
  protected function isAuthorized($user){
    //Are you an admin?
    $isAdmin = false; //Your magic business here
    return $isAdmin;
  }
}

Let's try with some routes and define the notAuthorized one:

<?php

$app->get("/guestRoute", function ($resquest, $response, $args) {
  return $response->write("You're a guest");
})->add(new \GuestAuthorization());


$app->get("/adminRoute", function ($resquest, $response, $args) {
  return $response->write("You're an admin");
})->add(new \AdminAuthorization());

$app->get("/notAuthorized", function ($resquest, $response, $args) {
  return $response->write("You're not authorized for this, my son!");
});

PROs:

  • you can handle in different ways the authorization for every role;
  • you can add multiple middlewares for a single route.

CONs:

  • you can't handle in this way dynamic roles;
  • one middleware for each role.

Upvotes: 1

Related Questions