Slim PHP: Only catch valid routes with middleware

半腔热情 提交于 2019-11-28 07:36:52

问题


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?


回答1:


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.




回答2:


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




回答3:


Maybe my implementation will work for you:

<?php

class CustomAuth extends \Slim\Middleware {

    public function hasRoute() {
        $dispatched = false;

        // copied from Slim::call():1312
        $matchedRoutes = $this->app->router->getMatchedRoutes($this->app->request->getMethod(), $this->app->request->getResourceUri());
        foreach ($matchedRoutes as $route) {
            try {
                $this->app->applyHook('slim.before.dispatch');
                $dispatched = $route->dispatch();
                $this->app->applyHook('slim.after.dispatch');
                if ($dispatched) {
                    break;
                }
            } catch (\Slim\Exception\Pass $e) {
                continue;
            }
        }

        return $dispatched;
    }

    public function call() {

        if ($this->hasRoute()) {
            if ($authorized) {
                $this->next->call();
            }
            else {
                $this->permissionDenied();
            }
        }
        else {
            $this->next->call();
        }
    }
}


来源:https://stackoverflow.com/questions/21881963/slim-php-only-catch-valid-routes-with-middleware

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!