Symfony X-CSRF-TOKEN 发送失败

问题描述 投票:0回答:1

在此代码中:

<?php

namespace App\Tests;

use ApiPlatform\Symfony\Bundle\Test\ApiTestCase;
use Symfony\Component\HttpClient\HttpClient;
use Symfony\Contracts\HttpClient\ResponseInterface;

class SuperApiTestCase extends ApiTestCase {
    
    public static function getBaseUrl(): ?string {
        return "https://localhost:8000";
    }

    public static function getShortSessionKey(): ?string {
        return "JWT_KEY";
    }

    public function sendRequest(string $url, string $methodType = 'GET'): ?ResponseInterface {
        $url = $this->getBaseUrl() . $url;

        $client = HttpClient::create();

        $response = $client->request($methodType, $url, [
            'headers' => [
                'Authorization' => 'Bearer ' . $this->getShortSessionKey(),
                'Accept' => 'application/json',
            ],
            'verify_peer' => false,  // Disable SSL verification
            'verify_host' => false,  // Disable host verification
        ]);

        return $response;
    }


    public function getCSRF(): ?string {
        $url = "/api/v1/config/csrf";

        $response = $this->sendRequest($url);

        $csrfData = $response->toArray();
        return $csrfData['csrf_token'];
    }
}
<?php

namespace App\Tests\Controller;

use App\Tests\SuperApiTestCase;
use Symfony\Component\HttpClient\HttpClient;
use Symfony\Component\HttpClient\Exception\ClientException;

class UserControllerTest extends SuperApiTestCase {
    
    public function testGetUsers() {

        $client = HttpClient::create([
            'verify_peer' => false,
            'verify_host' => false,
        ]);
        $csrfToken = $this->getCSRF();

        try {
            $response = $client->request('GET', 'https://localhost:8000/api/v1/user/', [
                'headers' => [
                    'Authorization' => 'Bearer ' . $this->getShortSessionKey(),
                    'Content-Type' =>  'application/json',
                    'X-CSRF-TOKEN' => $csrfToken,
                ],
                
            ]);
            
            print_r($response->getStatusCode());
            
            $statusCode = $response->getStatusCode();
            $content = $response->getContent();
            $data = $response->toArray();
        
            echo "Status Code: $statusCode\n";
            print_r($data);
        
        } catch (ClientException $e) {
            echo 'HTTP status code: ' . $e->getResponse()->getStatusCode() . PHP_EOL;
            echo 'Error: ' . $e->getMessage() . PHP_EOL;
            echo 'Response: ' . $e->getResponse()->getContent(false) . PHP_EOL;
        }
    }
}

用于检查 csrf token 的监听器:

<?php

namespace App\EventListener;

use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpKernel\Event\RequestEvent;
use Symfony\Component\Security\Core\Exception\InvalidCsrfTokenException;
use Symfony\Component\Security\Csrf\CsrfToken;
use Symfony\Component\Security\Csrf\CsrfTokenManagerInterface;

class CsrfTokenRequestListener {

    public function __construct(private CsrfTokenManagerInterface $csrfTokenManager) {
        
    }

    public function onKernelRequest(RequestEvent $event) {
        $request = $event->getRequest();
        $path = $request->getPathInfo();

        // Only apply to routes starting with /api/v1 but not /api/v1/config/csrf

        if(preg_match('/^\/api\/v1(?!\/config\/csrf)/', $path)) {
            $csrfToken = $request->headers->get('X-CSRF-TOKEN');

            if (!$csrfToken) {
                $event->setResponse(new JsonResponse(['error' => 'CSRF token is missing'], JsonResponse::HTTP_BAD_REQUEST));
                return;
            }

            try {
                $isValid = $this->csrfTokenManager->isTokenValid(new CsrfToken('csrf_token_id', $csrfToken));
            } catch (InvalidCsrfTokenException $e) {
                $event->setResponse(new JsonResponse(['error' => 'Invalid CSRF token 1'], JsonResponse::HTTP_BAD_REQUEST));
                return;
            }
            
            if (!$isValid) {
                $event->setResponse(new JsonResponse(['error' => 'Invalid CSRF token 2'], JsonResponse::HTTP_BAD_REQUEST));
                return;
            }
        }

    }
}

在 services.yaml 中注册:

    App\EventListener\CsrfTokenRequestListener:
        tags:
        - { name: kernel.event_listener, event: kernel.request, method: onKernelRequest, priority: 5 }

当我发送请求以获取用户数据时,它显示此错误,而它与 Postman 一起正常工作:

'error' => 'Invalid CSRF token 2'
php unit-testing symfony
1个回答
0
投票

问题在于:您发送了 2 个具有不同会话 ID 的请求,这导致了此问题。要解决此问题,您需要在标题中添加

PHPSESSID
及其值,如下所示:

$session_id = session_create_id()

$response = $client->request('GET', 'https://localhost:8000/api/v1/user/', [
    'headers' => [
        'Authorization' => 'Bearer ' . $this->getShortSessionKey(),
        'Content-Type' =>  'application/json',
        'X-CSRF-TOKEN' => $csrfToken,
        'Cookie' => 'PHPSESSID=' . $session_id
    ],
    
]);
最新问题
© www.soinside.com 2019 - 2024. All rights reserved.