【问题标题】:Simulating authentication in Symfony 2/Doctrine without database calls in functional tests在 Symfony 2/Doctrine 中模拟身份验证,而无需在功能测试中调用数据库
【发布时间】:2015-07-07 15:13:29
【问题描述】:

我正在尝试为我的应用程序编写一些功能测试,我遇到的问题是,除非我真的将用户从数据库中拉出,否则我无法让它使用新的用户对象。我想尽可能减少数据库查询的数量。

我所有的用户都存储在数据库中,并通过 Doctrine 层访问。以下是我如何进行安全设置以及目前的工作方式:

// app/security.yml

security:
providers:
    administrators:
        entity: { class: User, property: email }

encoders:
    User:
        algorithm: sha512

role_hierarchy:
    ROLE_ADMIN: ROLE_USER

firewalls:
    dev:
       pattern: ^/(_(profiler|wdt|error)|css|images|js)/
       security: false

    default:
        anonymous: ~
        http_basic: ~
        form_login:
            login_path: login
            check_path: login-check
            csrf_provider: security.csrf.token_manager
        logout:
            path: /logout
            target: login

access_control:
    - { path: ^/login$, role: IS_AUTHENTICATED_ANONYMOUSLY }
    - { path: ^/, role: ROLE_ADMIN }

通过关注http://symfony.com/doc/current/cookbook/testing/simulating_authentication.html 我有以下工作

$client = static::createClient();
$user = $client->getContainer()->get('doctrine')->getEntityManager()->getRepository('User')->findOneByEmail('nick@example.com');

$session = $client->getContainer()->get('session');

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

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

$crawler = $client->request('GET', '/some-secure-url');

$this->assertTrue($client->getResponse()->isSuccessful());

我想做的是:

$client = static::createClient();
$user = new User();
$user->setRoles(['ROLE_ADMIN']);

$session = $client->getContainer()->get('session');

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

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

$crawler = $client->request('GET', '/some-secure-url');

$this->assertTrue($client->getResponse()->isSuccessful());

但目前当我尝试这种方法时,我得到以下结果

You cannot refresh a user from the EntityUserProvider that does not contain an identifier. The user object has to be serialized with its own identifier mapped by Doctrine.

任何关于这方面的建议都会很棒:)

【问题讨论】:

    标签: php symfony doctrine-orm functional-testing


    【解决方案1】:

    这是因为用户提供者每次都会尝试使用UserProviderInterface::refreshUser() 刷新用户,即使它在会话中可用。

    这是默认行为,因为用户详细信息自上次从数据库中读取后可能已更改。此时更改此行为需要实现自定义用户提供程序(请参阅https://github.com/symfony/symfony/issues/1338)。

    最简单的解决方法是为您的用户添加一个标识符。如果我阅读了您的配置,您使用了电子邮件作为标识符:

    $user = new User();
    $user->setRoles(['ROLE_ADMIN']);
    $user->setEmail('foo@bar.com');
    

    Symfony 将对数据库进行查询,但它也会在真实场景中进行查询。如果你想改变这种行为,你需要provide your own implementation of the UserProviderInterface,它不会对每个请求进行查询。

    或者,在功能测试中使用另一种身份验证方法(如 http basic)。

    【讨论】:

    • 啊,不管怎样它都会调用 db(使用默认的 UserProvider),那么我会更好地集成基本 HTTP 身份验证以进行功能测试吗?
    猜你喜欢
    • 1970-01-01
    • 2013-11-04
    • 1970-01-01
    • 2013-11-12
    • 2019-12-28
    • 2020-10-25
    • 2021-03-28
    • 1970-01-01
    • 2020-04-11
    相关资源
    最近更新 更多