phpunit 测试用例中的基本身份验证

Basic Authentication in phpunit test case

我想到了在我的小脚本中使用 Basic Auth 的绝妙想法,因为我认为它会比使用 jwt 更快……我错了。我现在无法测试我的端点,因为我经常收到 401。

下面的源代码也可以在这里找到:https://github.com/tarach/blog-api/tree/feature/posts-resource-test

public function testShouldCreatePost(): void
    {
        $client = static::createClient();

        $headers = [
            'Content-Type' => 'application/json',
            'Authorization' => 'Basic ' . base64_encode('test:qwe123'),
        ];

        dump($headers);

        $client->request('POST', '/api/posts', [
            'headers' => $headers,
            'json' => [],
        ]);

        dump([
            'response' => [
                'status' => $client->getResponse()->getStatusCode(),
                'body' => $client->getResponse()->getContent(),
            ],
        ]);
    }

security.yaml

security:
    # https://symfony.com/doc/current/security.html#where-do-users-come-from-user-providers
    encoders:
        App\Infrastructure\Symfony\User\EnvironmentUser:
            algorithm: plaintext
    providers:
        environment_user_provider:
            id: App\Infrastructure\Symfony\User\EnvironmentUserProvider
    firewalls:
        dev:
            pattern: ^/(_(profiler|wdt)|css|images|js)/
            security: false
        main:
            pattern: ^/api
            stateless: true
            anonymous: true
            provider: environment_user_provider
            http_basic:
                realm: Protected

    access_control:
         - { path: ^/api/posts, methods: ["GET"], roles: IS_AUTHENTICATED_ANONYMOUSLY }
         - { path: ^/api/docs, roles: IS_AUTHENTICATED_ANONYMOUSLY }
         - { path: ^/api,       roles: IS_AUTHENTICATED_FULLY }

EnvironmentUserProvider 使用两个环境。变量 USER_NAME 和 USER_PASSWORD。 通过 Postman 它可以正常工作:

解决方案:

public function testShouldCreatePost(): void
    {
        // Method A)
        $client = static::createClient([], [
            'PHP_AUTH_USER' => 'test',
            'PHP_AUTH_PW'   => 'qwe123',
        ]);

        // Method B)
        $client->setServerParameter('HTTP_AUTHORIZATION', 'Basic ' . base64_encode('test:qwe123'));

        $content = json_encode([
            'title' => 'Some title',
            'body' => '<strong>Some Body</strong>'
        ]);

        $client->request(
            'POST',
            '/api/posts',
            [],
            [],
            [
                'CONTENT_TYPE' => 'application/json',
            ],
            $content
        );

        $this->assertEquals(201, $client->getResponse()->getStatusCode());
    }

如果您使用最新的 Symfony 版本(5.1 或更高版本),您可以使用客户端上的简洁助手:

$client = static::createClient();
$userRepository = static::$container->get(UserRepository::class);

// retrieve the test user
$testUser = $userRepository->findOneByEmail('john.doe@example.com');

// simulate $testUser being logged in
$client->loginUser($testUser);

// test e.g. the profile page
$client->request('GET', '/profile');

示例取自 Logging in Users in Tests.

的文档

如果您使用基本身份验证,您可以像这样为身份验证对话框传递凭据:

$client = static::createClient([], [
    'PHP_AUTH_USER' => 'username',
    'PHP_AUTH_PW'   => 'pa$$word',
]);

How to Simulate HTTP Authentication in a Functional Test.

的旧文档中所示

如果您想提交示例中的 headers,事情会有点棘手,因为您需要传入内部表示,如 BrowserKit Browser.[=17 中所示=]

在您的情况下,headers 可能应该像这样更改:

$headers = [
    'CONTENT_TYPE' => 'application/json',
    'HTTP_AUTHORIZATION' => 'Basic ' . base64_encode('test:qwe123'),
];

您可以看到 Symfony 在 HttpFoundation ServerBag.

的代码中使用了哪种内部表示