我正在尝试禁用单个控制器(API)的CSRF检查,但我无法找到我是如何实现这一点的。
使用以下命令可以在特定请求中禁用3.5.0之前的CSRF组件:
$this->eventManager()->off($this->Csrf);
有两种方法可以做到这一点。
根据您创建的路由,您可以仅将中间件应用于特定范围,例如:
// config/routes.php
use Cake\Http\Middleware\CsrfProtectionMiddleware;
Router::scope('/', function ($routes) {
$routes->registerMiddleware('csrf', new CsrfProtectionMiddleware([
'httpOnly' => true
]));
$routes->scope('/api', function ($routes) {
// ...
});
$routes->scope('/blog', function ($routes) {
$routes->applyMiddleware('csrf');
// ...
});
$routes->scope('/cms', function ($routes) {
$routes->applyMiddleware('csrf');
// ...
});
});
这将仅将CSRF中间件应用于blog
和cms
范围内连接的路由。
还可以将范围进一步缩小到路由级别,并将中间件应用于特定路由:
$routes
->connect('/blog/:action', ['controller' => 'Blogs'])
->setMiddleware(['csrf']);
这将CSRF中间件仅应用于/blog/*
路由。
另一种方法是在适用时手动应用中间件。为了能够做到这一点,您必须创建一个自定义中间件处理程序,以便您可以访问当前请求对象,从中可以提取controller
参数,然后您必须在处理程序内调用CSRF中间件,有点像这样:
// src/Application.php
// ...
use Cake\Http\Middleware\CsrfProtectionMiddleware;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
class Application extends BaseApplication
{
// ...
public function middleware($middleware)
{
$middleware
// ...
->add(new RoutingMiddleware())
->add(function (
ServerRequestInterface $request,
ResponseInterface $response,
callable $next
) {
$params = $request->getAttribute('params');
if ($params['controller'] !== 'Api') {
$csrf = new CsrfProtectionMiddleware([
'httpOnly' => true
]);
// This will invoke the CSRF middleware's `__invoke()` handler,
// just like it would when being registered via `add()`.
return $csrf($request, $response, $next);
}
return $next($request, $response);
});
return $middleware;
}
}
请注意,您必须在路由中间件之后应用自定义中间件,因为这是设置控制器信息的位置。
如果适用,您还可以针对请求URL而不是路由参数进行测试,例如:
if (mb_strpos($request->getUri()->getPath(), '/api/') === false) {
$csrf = new CsrfProtectionMiddleware([
'httpOnly' => true
]);
return $csrf($request, $response, $next);
}
这样做时,自定义中间件不会被限制放置在路由中间件之后,理论上你可以把它放在你想要的任何位置。
我认为在Cake 3.6中,你应该从中间件中删除CsrfProtectionMiddleware:
queue:src / Application.php
public function middleware($middlewareQueue)
{
$middlewareQueue
// Catch any exceptions in the lower layers,
// and make an error page/response
->add(ErrorHandlerMiddleware::class)
// Handle plugin/theme assets like CakePHP normally does.
->add(new AssetMiddleware([
'cacheTime' => Configure::read('Asset.cacheTime')
]))
// Add routing middleware.
// Routes collection cache enabled by default, to disable route caching
// pass null as cacheConfig, example: `new RoutingMiddleware($this)`
// you might want to disable this cache in case your routing is extremely simple
->add(new RoutingMiddleware($this, '_cake_routes_'));
// Add csrf middleware.
// ->add(new CsrfProtectionMiddleware([
// 'httpOnly' => true
// ]));
return $middlewareQueue;
}