我正在用Slim编写REST API.我编写了一个小型中间件来保护资源,因此只有经过身份验证的用户才能访问它们:
<?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;
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
这是有效的,但不希望的副作用是中间件不区分现有路由和不存在的路由.例如,如果用户尝试请求/dfghdfgh不存在的路由,而不是获得404的HTTP状态代码,则他将得到403表示没有访问令牌.我想在中间件类上添加类似于以下检查的实现:
if ($app->hasRoute($app->request->getPathInfo()){
$this->next->call(); //let go so user gets 404 from the app.
}
Run Code Online (Sandbox Code Playgroud)
任何想法如何实现这一目标?
不完全是你所要求的,但就个人而言,当我需要检查某些路线上的身份验证时,我会这样做。
配置:
$config = array(
...,
'user.secured.urls' => array(
array('path' => '/user'),
array('path' => '/user/'),
array('path' => '/user/.+'),
array('path' => '/api/user/.+')
),
...
);
Run Code Online (Sandbox Code Playgroud)
中间件:
/**
* 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();
}
Run Code Online (Sandbox Code Playgroud)
但如果几乎所有路由都需要身份验证可能不是最好的解决方案。
很好的例子:http ://www.slideshare.net/jeremykendall/keeping-it-small-slim-php