首页 > 解决方案 > phpunit 测试用例中的基本身份验证

问题描述

我想出了一个在我的小脚本中使用 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(),
            ],
        ]);
    }

在此处输入图像描述

安全.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。通过邮递员它可以正常工作: 在此处输入图像描述

解决方案

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());
    }

标签: phpsymfonyphpunitbasic-authenticationapi-platform.com

解决方案


如果您使用最新的 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 中所见。

如果您想提交示例中的标头,事情有点棘手,因为您需要传入内部表示,如BrowserKit Browser中所示。

在您的情况下,标题可能应该像这样改变:

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

您可以在HttpFoundation ServerBag的代码中看到 Symfony 使用的内部表示。


推荐阅读