2

我正在构建一个基于 slim3 框架的网上商店。我需要处理服务器到服务器的 POST 请求以确认付款是否成功。我将 csrf 添加到容器中,如下所示:

$container['csrf'] = function($container) {
    return new \Slim\Csrf\Guard;
};

并将其添加到应用程序中,如下所示:

$app->add($container->csrf);

而且效果很好。但是现在我需要能够为某个路由添加一个例外,这样我才能得到他们发送的发布请求。到目前为止,我找不到可行的解决方案。

有什么建议吗?

4

3 回答 3

5

如果您需要从中间件中排除一条路由,有两种选择:

选项 1:对您的路线进行分组。

您可以对所有路线进行分组,但以下路线除外:

<?php
$app->group('', function() {

    // All routes declarations....

})->add($container->csrf); // Add middleware to all routes within the group

// Declare your "exceptional" route outside the group
$app->post('my-special-route-that-has-no-csrf-middleware', 'routeProcessor');

选项 2:使用您自己的中间件

不要直接使用,而是\Slim\Csrf\Guard使用您自己的扩展它的中间件。您的中间件将检查路由,如果路由是“异常”路由,它将跳过。

将此添加到设置中,因为您需要在中间件中访问路由:

$container['settings'] => [
    'determineRouteBeforeAppMiddleware' => true
];

创建中间件扩展原始\Slim\Csrf\Guard

<?php
class MyCsrfMiddleware extends Slim\Csrf\Guard
{
    // This method is processing every request in your application
    public function processRequest($request, $response, $next) {
        // Check if it's your "exceptional" route
        $route = $request->getAttribute('route');
        if ($route == 'my-special-path') {
            // If it is - just pass request-response to the next callable in chain
            return $next($request, $response);
        } else {
            // else apply __invoke method that you've inherited from \Slim\Csrf\Guard
            return $this($request, $response, $next);
        }
    }
}

/////////////

$container['csrf'] = function($container) {
    return new MyCsrfMiddleware; // Now the container returns your middleware under 'csrf' key
};

现在只需将中间件添加到\Slim\App实例:

$app->add('csrf:processRequest');
于 2016-10-26T20:47:48.220 回答
2

如果有人仍在为此烦恼(尤其是如果您想使用 webhook),则不会。

在 Georgy 的回答的帮助下,我找到了一个更简单的解决方案。

只需对实际的Slim\Csrf\Guard 'Guard.php'文件及其__invoke方法进行以下修改。或者只是复制并粘贴下面的代码......

public function __invoke(ServerRequestInterface $request, ResponseInterface $response, callable $next)
{

  $route = $request->getAttribute('routeInfo');

  $routeRequestInfo = $route['request'];

  $requestUrl = $routeRequestInfo[1];


  if ($requestUrl == 'http://yoursite/the-url-you-want-to-exempt')
  {
      //This will just return the request to your application with applying the csrf.
      return $next($request, $response);

  }
  else
  {

    $this->validateStorage();

    // Validate POST, PUT, DELETE, PATCH requests
    if (in_array($request->getMethod(), ['POST', 'PUT', 'DELETE', 'PATCH'])) {
        $body = $request->getParsedBody();
        $body = $body ? (array)$body : [];
        $name = isset($body[$this->prefix . '_name']) ? $body[$this->prefix . '_name'] : false;
        $value = isset($body[$this->prefix . '_value']) ? $body[$this->prefix . '_value'] : false;
        if (!$name || !$value || !$this->validateToken($name, $value)) {
            // Need to regenerate a new token, as the validateToken removed the current one.
            $request = $this->generateNewToken($request);

            $failureCallable = $this->getFailureCallable();
            return $failureCallable($request, $response, $next);
        }
    }

    // Generate new CSRF token if persistentTokenMode is false, or if a valid keyPair has not yet been stored
    if (!$this->persistentTokenMode || !$this->loadLastKeyPair()) {
        $request = $this->generateNewToken($request);
    }

    // Enforce the storage limit
    $this->enforceStorageLimit();

  }

    return $next($request, $response);
}
于 2017-05-06T23:04:05.993 回答
0
$container['csrf'] = function($container) {
    $guard = new \Slim\Csrf\Guard;
    $guard->setFailureCallable(function($request, $response, $next) use ($container) {
        $request = $request->withAttribute("csrf_status", false);
        if($request->getAttribute('csrf_status') === false) {
           if($request->getAttribute('route')->getName()=== 'your-route-name'){
            return $next($request, $response);
           }
            return $response->withStatus(400)->withRedirect($container['router']->pathFor('home'));
        } else {
            return $next($request, $response);
        }
    });

    return $guard;
};
于 2018-02-17T15:06:47.067 回答