在此代码中:
<?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'
问题在于:您发送了 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
],
]);