我试图为我的应用程序编写一些功能测试,我遇到的问题是,除非我真的将用户从数据库中拉出来,否则我无法使用新的用户对象。我希望尽可能减少数据库查询量。
我的所有用户都存储在数据库中,并通过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.
对此有任何建议都很棒:)
答案 0 :(得分:0)
这是因为用户提供商每次都会尝试使用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)和功能测试。