Несоответствие токена CSRF в тестах cakephp3.7 - PullRequest
1 голос
/ 16 мая 2019

tests / TestCase / Controller / FeedbackControllerTest.php: 45

public function testAdd()
{
    $this->enableCsrfToken();
    $this->enableSecurityToken();
    $this->session([
        'Auth' => [
            'User' => [
                'id' => 1,
                'role' => 'REPR',
            ]
        ]
    ]);
    $this->configRequest([
        'headers' => ['Accept' => 'application/json']
    ]);
    $_data = [
        'crash' => 1,
        'details' => 'Lorem ipsum dolor sit amet'
    ];
    $_data = json_encode($_data, JSON_PRETTY_PRINT);
    $this->post('/feedback/add', $_data); // <---- 45
    $expected = [
        'status' => 'success'
    ];
    $expected = json_encode($expected, JSON_PRETTY_PRINT);
    $this->assertEquals($expected, (string)$this->_response->getBody());
}

Выход PHPUnit:

1) App\Test\TestCase\Controller\FeedbackControllerTest::testAdd
Cake\Http\Exception\InvalidCsrfTokenException: Missing CSRF token cookie

/vagrant/vendor/cakephp/cakephp/src/Http/Middleware/CsrfProtectionMiddleware.php:196
/vagrant/vendor/cakephp/cakephp/src/Http/Middleware/CsrfProtectionMiddleware.php:120
/vagrant/vendor/cakephp/cakephp/src/Http/Middleware/CsrfProtectionMiddleware.php:106
/vagrant/vendor/cakephp/cakephp/src/Http/Runner.php:65
/vagrant/vendor/cakephp/cakephp/src/Http/Runner.php:51
/vagrant/vendor/cakephp/cakephp/src/Routing/Middleware/RoutingMiddleware.php:168
/vagrant/vendor/cakephp/cakephp/src/Http/Runner.php:65
/vagrant/vendor/cakephp/cakephp/src/Routing/Middleware/AssetMiddleware.php:88
/vagrant/vendor/cakephp/cakephp/src/Http/Runner.php:65
/vagrant/vendor/cakephp/cakephp/src/Error/Middleware/ErrorHandlerMiddleware.php:96
/vagrant/vendor/cakephp/cakephp/src/Http/Runner.php:65
/vagrant/vendor/cakephp/cakephp/src/Http/Runner.php:51
/vagrant/vendor/cakephp/cakephp/src/Http/Server.php:98
/vagrant/vendor/cakephp/cakephp/src/TestSuite/MiddlewareDispatcher.php:201
/vagrant/vendor/cakephp/cakephp/src/TestSuite/IntegrationTestTrait.php:516
/vagrant/vendor/cakephp/cakephp/src/TestSuite/IntegrationTestTrait.php:413
/vagrant/tests/TestCase/Controller/FeedbackControllerTest.php:45

Я прочитали попробуйте решения из ответов:

Как создать токен CSRF для тестирования Cakephp 3 PHPunit?

, если я добавлю как @ndm говорит:

$token = 'my-csrf-token';

$this->cookie('csrfToken', $token);

$data = [
    'email' => 'info@example.com',
    'password' => 'secret',
    '_csrfToken' => $token
];

Тогда:

Cake \ Http \ Exception \ InvalidCsrfTokenException: несоответствие токена CSRF.

Как исправить?

Ответы [ 2 ]

1 голос
/ 17 мая 2019

При передаче строки в качестве данных POST тестовый пример интеграции не устанавливает автоматически токены, ни токен CSRF, ни токен безопасности, поскольку он не может ничего вставить в строку, не зная о формате данных. Следовательно, он также не будет устанавливать cookie.

Таким образом, в случаях, когда вы передаете строковые данные, вам необходимо установить cookie и токен вручную, аналогично тому, как описано в ответе, который вы связали. Однако при использовании чего-либо, кроме application/x-www-form-urlencoded данных (то есть данных, которые PHP будет декодировать и помещать в суперглобальный $_POST), в вашем примере данных JSON вы должны передать токен в качестве заголовка, поскольку входные данные JSON будут декодируется компонентом обработчика запросов (есть планы переместить это на уровень промежуточного программного обеспечения IIRC), который запускает после промежуточного программного обеспечения CSRF, который, следовательно, не будет видеть никаких данных постов.

Пример:

$token = 'my-csrf-token';
$this->cookie('csrfToken', $token);

$this->configRequest([
    'headers' => [
        'X-CSRF-Token' => $token,
        // ...
    ]
]);

С другой стороны, токены компонента безопасности должны были бы идти в данных POST, компонент безопасности не будет искать заголовки, и он будет иметь доступ к декодированным данным после запуска компонента обработчика запросов (убедитесь, что вы загрузить компонент обработчика запросов до компонента безопасности!). Вы можете обратиться к источнику \Cake\TestSuite\IntegrationTestTrait::_addTokens(), чтобы выяснить, как создаются токены безопасности, вы бы сделали это примерно так:

$url = '/feedback/add';

$_data = [
    'crash' => 1,
    'details' => 'Lorem ipsum dolor sit amet'
];

$keys = array_map(
    function ($field) {
        return preg_replace('/(\.\d+)+$/', '', $field);
    },
    array_keys(Hash::flatten($_data))
);

$tokenData = $this->_buildFieldToken($url, array_unique($keys));

$_data['_Token'] = $tokenData;
$_data['_Token']['debug'] = 'SecurityComponent debug data would be added here';

Обратите внимание, что URL, который передается на _buildFieldToken(), также должен включать возможные данные строки запроса!

0 голосов
/ 17 мая 2019

Можете ли вы попробовать этот код в вашей функции jquery ajax,

beforeSend: function (xhr) 
{
    xhr.setRequestHeader('X-CSRF-Token', $('[name="_csrfToken"]').val());
},

поставить код перед функцией успеха

...