在功能测试中使用令牌模拟身份验证时如何正确设置用户名

How to properly set the username when simulating authentication with a token in a functional test

我需要编写一个功能测试来测试每个角色是否可以正确访问页面。

为了做到这一点,我是 simulating authentication with a token,但我稍微编辑了 logIn 方法,只是为了用自定义 $username$role 和 [=15= 调用它]:

protected function logIn($username, $role, $firewall)
{
    $session = $this->client->getContainer()->get('session');

    $token = new UsernamePasswordToken($username, null, $firewall, $role);
    $session->set('_security_' . $firewall, serialize($token));
    $session->save();

    $cookie = new Cookie($session->getName(), $session->getId());
    $this->client->getCookieJar()->set($cookie);
}

所以我可以调用它来指定哪些角色应该拥有假用户:

    $this->logIn('my_username@example.com', ['ROLE_USER'], "my_firewall");

然后我可以测试是否允许或不允许用户访问某些路由:

// check if the access is correctly denied to the ROLE_USER
$this->client->request('GET', '/route-not-allowed-to-user');
        $this->assertEquals(403, $this->client->getResponse()->getStatusCode());

// check if the access is correctly allowed to the ROLE_USER
$this->client->request('GET', '/route-allowed-to-user');
        $this->assertNotEquals(403, $this->client->getResponse()->getStatusCode());

这些断言有效,唯一的问题是 route-allowed-to-user 我正在使用 twig 输出用户名:

{{ app.user.username }}

但是失败了。我得到状态代码 500 而不是 200,并且出现以下错误:

Impossible to access an attribute ("username") on a null variable ...

因为app.user没有设置。

模拟token认证时如何正确设置用户?

我认为发生这种情况是因为您没有通过身份验证过程,只是创建了用户令牌,它没有触发存储用户用户名、角色等的 Symfony 事件。

我最近做了类似的事情,实际上是通过登录表单、填写数据并发送。就像我在进行真正的登录尝试一样,效果很好。

use Symfony\Component\DependencyInjection\ContainerInterface;

abstract class AuthenticatedTestCase extends KernelTestCase
{
    static protected $client;

    static public function setUpBeforeClass()
    {
        parent::setUpBeforeClass();
        self::$client = static::$kernel->getContainer()->get('test.client');
    }

    static public function login($login, $password)
    {    
        $crawler = self::$client->request('GET', '/test_admin/login');
        $form = $crawler->filter('input[type="submit"]')->form([
            '_username' => $login,
            '_password' => $password,
        ]);

        self::$client->submit($form);

        // Redirect after successful login
        self::assertEquals(302, self::$client->getResponse()->getStatusCode());

        self::$client->followRedirect();

        if (200 === self::$client->getResponse()->getStatusCode()) {
            // Redirected URL is OK
            // ...
        }
    }
}

我通过如下编辑 logIn 方法解决了问题:

protected function logIn($username, $password, $firewall)
{
    $session = $this->client->getContainer()->get('session');
    $authenticationManager = $this->client->getContainer()->get('security.authentication.manager');

    $token = $authenticationManager->authenticate(
        new UsernamePasswordToken(
            $username,
            $password,
            $firewall
        )
    );

    $session->set('_security_' . $firewall, serialize($token));
    $session->save();

    $cookie = new Cookie($session->getName(), $session->getId());
    $this->client->getCookieJar()->set($cookie);
}

并使用 doctrine data fixtures 来设置用户和角色。