Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Slim PHP: Only catch valid routes with middleware

Tags:

php

slim

I'm writing a REST API with Slim. I have written a small middleware to protect the resources so only authenticated users will be able to access them:

<?php
class SecurityMiddleware extends \Slim\Middleware
{
    protected $resource;
    public function __construct($resource)
    {
        $this->resource = $resource;
    }
    public function call()
    {
        //get a reference to application
        $app = $this->app;
        //skip routes that are exceptionally allowed without an access token:
        $publicRoutes = ["/","/login","/about"];
        if (in_array($app->request()->getPathInfo(),publicRoutes)){
            $this->next->call(); //let go
        } else {
            //Validate:
            if ($this->resource->isValid()){
                $this->next->call(); //validation passed, let go
            } else {
                $app->response->setStatus('403'); //validation failed
                $app->response->body(json_encode(array("Error"=>"Access token problem")));
                return;
            }
        }
    }
}

This works, but the undesired side effect is the middleware does not make a distinction between existing routes and non-existing routes. For example, if a the user attempts to request a route like /dfghdfgh which does not exist, instead of getting an HTTP status code of 404 he'll get a 403 saying there is no access token. I would like to add an implementation similar to the following check on the middleware class:

if ($app->hasRoute($app->request->getPathInfo()){
    $this->next->call(); //let go so user gets 404 from the app.
}

Any ideas how this can be achieved?

like image 452
user1555863 Avatar asked Feb 19 '14 13:02

user1555863


2 Answers

I use a hook to do what you're trying to do, as MamaWalter suggested, but you want to use slim.before.dispatch rather than an earlier hook. If the route your user is trying to visit doesn't exist, the hook will never be called and the 404 gets thrown.

I'm doing exactly that in my own Authorization Middleware. Works like a charm.

like image 182
Jeremy Kendall Avatar answered Sep 24 '22 22:09

Jeremy Kendall


Not exactly what you asking for, but personnaly when i need to check authentification on some routes i do it like this.

config:

$config = array(
    ...,

    'user.secured.urls' => array(
        array('path' => '/user'),
        array('path' => '/user/'),
        array('path' => '/user/.+'),
        array('path' => '/api/user/.+')
    ),
    ...

);

middleware:

/**
 * Uses 'slim.before.router' to check for authentication when visitor attempts
 * to access a secured URI.   
 */
public function call()
{
    $app = $this->app;
    $req = $app->request();
    $auth = $this->auth;
    $config = $this->config;

    $checkAuth = function () use ($app, $auth, $req, $config) {

        // User restriction
        $userSecuredUrls = isset($config['user.secured.urls']) ? $config['user.secured.urls'] : array();
        foreach ($userSecuredUrls as $url) {
            $urlPattern = '@^' . $url['path'] . '$@';
            if (preg_match($urlPattern, $req->getPathInfo()) === 1 && $auth->hasIdentity() === false) {

            $errorData = array('status' => 401,'error' => 'Permission Denied');
            $app->render('error.php', $errorData, 401);
            $app->stop();                   
        }
    }

    };

    $app->hook('slim.before.router', $checkAuth);

    $this->next->call();
}

but if almost all your routes need authentification maybe not the best solution.

great example: http://www.slideshare.net/jeremykendall/keeping-it-small-slim-php

like image 41
MamaWalter Avatar answered Sep 22 '22 22:09

MamaWalter