Я пишу REST API с Slim. Я написал небольшое промежуточное программное обеспечение для защиты ресурсов, поэтому доступ к ним могут получить только прошедшие проверку подлинности пользователи:
<?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; } } } }
Это работает, но нежелательным побочным эффектом является то, что промежуточное ПО не проводит различия между существующими маршрутами и несуществующими маршрутами. Например, если пользователь пытается запросить маршрут, например /dfghdfgh
который не существует, вместо получения кода статуса HTTP 404 он получит сообщение 403, в котором нет токена доступа. Я хотел бы добавить реализацию, аналогичную следующей проверке класса промежуточного ПО:
if ($app->hasRoute($app->request->getPathInfo()){ $this->next->call(); //let go so user gets 404 from the app. }
Есть идеи, как это можно достичь?
Я использую крючок, чтобы делать то, что вы пытаетесь сделать, как предполагал MamaWalter, но вы хотите использовать slim.before.dispatch
а не ранний крючок. Если маршрут, который ваш пользователь пытается посетить, не существует, крючок никогда не будет вызываться, а 404
будет выброшен.
Я делаю именно это в своем собственном промежуточном ПО авторизации . Работает как шарм.
Не совсем то, что вы просите, но personnaly, когда мне нужно проверить аутентификацию на некоторых маршрутах, я делаю это так.
конфигурации:
$config = array( ..., 'user.secured.urls' => array( array('path' => '/user'), array('path' => '/user/'), array('path' => '/user/.+'), array('path' => '/api/user/.+') ), ... );
промежуточный слой:
/** * 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(); }
но если почти все ваши маршруты требуют аутентификации, возможно, это не лучшее решение.
отличный пример: http://www.slideshare.net/jeremykendall/keeping-it-small-slim-php
Возможно, моя реализация будет работать на вас:
<?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(); } } }