我正在使用Twig前端开发基于Slim 3的应用程序,我也在制作REST API。
我已经为整个应用程序实现了slimphp \ Slim-Csrf,但我现在想要从每个" API"中排除这个CSRF检查。路由。
我试图实施"选项2"这篇文章: Slim3 exclude route from CSRF Middleware
以下是代码:
文件App \ Middleware \ CsrfMiddleware.php:
namespace App\Middleware;
class CsrfMiddleware extends \Slim\Csrf\Guard {
public function processRequest($request, $response, $next) {
// Check if this route is in the "Whitelist"
$route = $request->getAttribute('route');
if ($route->getName() == 'token') {
var_dump('! problem HERE, this middleware is executed after the CsrfMiddleware !');
// supposed to SKIP \Slim\Csrf\Guard
return $next($request, $response);
} else {
// supposed to execute \Slim\Csrf\Guard
return $this($request, $response, $next);
}
}
}
文件app \ app.php:
$app = new \Slim\App([
'settings' => [
'determineRouteBeforeAppMiddleware' => true
]
]);
require('container.php');
require('routes.php');
$app->add($container->csrf);
$app->add('csrf:processRequest');
文件app \ container.php:
$container['csrf'] = function ($container) {
return new App\Middleware\CsrfMiddleware;
};
文件app \ routes.php:
<?php
$app->get('/', \App\PagesControllers\LieuController::class.':home')->setName('home');
$app->post('/api/token', \App\ApiControllers\AuthController::class.'postToken')->setName('token');
当我在http://localhost/slim3/public/api/token上发出POST请求时,我已经:
CSRF检查失败!字符串(70)&#34;!问题在这里,这个中间件是在CsrfMiddleware之后执行的!&#34;
就像我的CsrfMiddleware在\ Slim \ Csrf \ Guard ...
之后执行一样有人有想法吗?
谢谢。
答案 0 :(得分:1)
在Slim 3中,中间件是LIFO(后进先出)。 以相反的方向添加中间件:
之前
$app->add($container->csrf);
$app->add('csrf:processRequest');
后
$app->add('csrf:processRequest');
$app->add($container->csrf);
注意:public
目录不应该是网址的一部分
不正确:http://localhost/slim3/public/api/token
正确:http://localhost/slim3/api/token
要跳过中间件中的处理,只需返回$ response对象。
// supposed to SKIP \Slim\Csrf\Guard
return $response;
答案 1 :(得分:0)
这是我通过Slim 3实现此目标的方法。
1)创建一个扩展\ Slim \ Csrf \ Guard的类,如下所示。
CsrfGuardOverride类是启用或禁用路径的CSRF检查的关键。如果当前路径已列入白名单,则__invoke()方法将跳过核心CSRF检查,并通过执行下一个中间件层继续进行。
如果当前路径不在白名单中(即应检查CSRF),则__invoke方法将按照其父\ Slim \ Csrf \ Guard :: __ invoke()来以常规方式处理CSRF。
<?php
namespace App\Middleware;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use \Slim\Csrf\Guard;
class CsrfGuardOverride extends Guard {
/**
* Invoke middleware
*
* @param ServerRequestInterface $request PSR7 request object
* @param ResponseInterface $response PSR7 response object
* @param callable $next Next middleware callable
*
* @return ResponseInterface PSR7 response object
*/
public function __invoke(ServerRequestInterface $request, ResponseInterface $response, callable $next)
{
// Set the name of the route we want whitelisted with a name
// prefix of 'whitelist'. check for that here, and add
// any path to the white list
$route = $request->getAttribute('route');
$routeName = $route->getName();
$whitelisted = strpos($routeName, 'whitelist');
// if url is whitelisted from being CSRF checked, then bypass checking by skipping directly to next middleware
if ($whitelisted !== FALSE) {
return $next($request, $response);
}
return parent::__invoke($request, $response, $next);
}
}
2)注册CsrfGuardOverride类。确保设置settings.determineRouteBeforeAppMiddleware => true
,因为这会强制Slim在执行任何中间件之前评估路由。
// Method on App Class
protected function configureContainer(ContainerBuilder $builder)
{
parent::configureContainer($builder);
$definitions = [
'settings.displayErrorDetails' => true,
'settings.determineRouteBeforeAppMiddleware' => true,
// Cross-Site Request Forgery protection
\App\Middleware\CsrfGuardOverride::class => function (ContainerInterface $container) {
$guard = new \App\Middleware\CsrfGuardOverride;
$guard->setPersistentTokenMode(true); // allow same CSRF token for multiple ajax calls per session
return $guard;
},
'csrf' => DI\get(\App\Middleware\CsrfGuardOverride::class),
// add others here...
];
$builder->addDefinitions($definitions);
}
3)通过绕过CSRF检查来添加所需的路径,并为其添加名称以“ whitelist”为前缀:
$app->post('/events/purchase', ['\App\Controllers\PurchaseController', 'purchaseCallback'])->setName('whitelist.events.purchase');