В настоящее время я переношу проект 2.0. * На текущую версию 2.1 Symfony.
В моих функциональных тестах я в настоящее время имею этот код для создания клиента с аутентификацией:
$client = // create a normal test client $role = 'ROLE_USER'; $firewallName = 'main'; $user = // pull a user from db $client->getCookieJar()->set(new \Symfony\Component\BrowserKit\Cookie(session_name(), true)); $token = new UsernamePasswordToken($user, null, $firewallName, array($role)); self::$kernel->getContainer()->get('session')->set('_security_' . $firewallName, serialize($token));
это работает как ожидается в 2.0. *, но не в 2.1, данные не будут установлены в сеансе.
Есть идеи?
Изменить (добавление дополнительной информации):
кажется, что проблема заключается в файле « Symfony \ Component \ Security \ Http \ Firewall \ ContextListener » в методе « onKernelResponse ». Существует этот код:
if ((null === $token = $this->context->getToken()) || ($token instanceof AnonymousToken)) { $session->remove('_security_'.$this->contextKey); } else { $session->set('_security_'.$this->contextKey, serialize($token)); }
в моем случае, если «$ token instanceof AnonymousToken» является истинным, и из-за этого ключ сеанса удаляется. если я прокомментирую этот код, все работает так, как ожидалось.
Поэтому, я думаю, мой новый вопрос: что я могу сделать, чтобы маркер не был анонимным?
Правильный способ аутентификации пользователя:
$firewallName = 'your-firewall-name'; $container = self::$kernel->getContainer() $token = new UsernamePasswordToken($user, null, $firewallName, $user->getRoles()); $container->get('security.context')->setToken($token);
и аутентификация межсетевого экрана:
$session = $container->get('session'); $session->set('_security_'.$firewallName, serialize($token)); $session->save();
Я зарегистрировал билет по адресу : https://github.com/symfony/symfony/issues/3287
По-видимому, существует проблема с Symfony 2.1 RC.
В моем testuite (работает с 2.0 и теперь 2.1) я использую базовый класс WebTestCase, который расширяет класс Symfony2 WebTestCase.
У меня есть две функции, которые создают анонимный клиент или зарегистрированный в моих тестах:
static protected function createClient(array $options = array(), array $server = array()) { $client = parent::createClient($options, $server); self::$container = self::$kernel->getContainer(); return $client; } protected function createAuthClient($user, $pass) { return self::createClient(array(), array( 'PHP_AUTH_USER' => $user, 'PHP_AUTH_PW' => $pass, )); }
Затем в моих тестовых классах я использую:
$client = static::createClient();
для создания анонимного клиента и
$client = static::createAuthClient('user','pass');
для создания аутентифицированного.
Это работает как шарм 2.1
Я могу предложить другое решение (таким образом, он работает для меня). У меня есть собственный поставщик проверки подлинности, со сложной логикой, и я не могу использовать http_basic mechanic вообще.
Вам нужно создать специальное действие, подобное этому
//TestAuthController.php public function authTestAction(Request $request) { // you can add different security checks as you wish $user_id = $request->query->get("id"); // find user by $user_id using service or user provider service from firewall config $token = new UsernamePasswordToken($user, null, $firewallName, array($role)); // or another authenticated token $this->container->get('security.context')->setToken($token); }
добавьте routing_test.yml и подключите его так же, как routing_dev.yml
Важно, что этот путь аутентификации должен существовать только в тестовой среде по соображениям безопасности.
//app/config/routing_test.yml // ... the same routes as in routing_dev.yml _testauth: pattern: /__test defaults: { _controller: MyBundle:TestAuth:authTest }
Затем в тесте просто отправьте клиент на этот URL-адрес
public function testSomething() { $client = static::createClient(); $client->request('GET','/__test',array('id'=>146)); $this->assertTrue($client->getContainer()->get('security.context')->isGranted('ROLE_USER')) //it will pass; }
У меня была та же проблема и я нашел решение во время отладки. В зависимости от вашего хранилища сеансов вам может потребоваться изменить ваш файл cookie с session_name () на «MOCKSESSID» (который используется, если вы используете сеанс mock. Я думаю, что если в вашем файле config_test.yml есть следующее: оно автоматически изменяется на Mock Хранение сеансов:
framework: test: ~
Для полноты, здесь мой полный код (я использую FOS / UserBundle)
protected function createAuthorizedClient($username = 'user') { $client = $this->createClient(); //Normal WebTestCase client $userProvider = $this->get('fos_user.user_manager'); $user = $userProvider->loadUserByUsername($username); //$client->getCookieJar()->set(new Cookie(session_name(), true)); $client->getCookieJar()->set(new Cookie('MOCKSESSID', true)); $session = self::$kernel->getContainer()->get('session'); $token = new UsernamePasswordToken($user, null, 'main', $user->getRoles()); $client->getContainer()->get('security.context')->setToken($token); $session->set('_security_main', serialize($token)); return $client; }