Подтвердить что ты не робот

Аутентификация в функциональных тестах в Symfony 2.1

В настоящее время я переношу проект 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));
}

в моем случае if, если "$ token instanceof AnonymousToken" истинно, и из-за этого ключ сеанса удаляется. если я прокомментирую этот код, все работает так, как ожидалось.

Итак, я думаю, мой новый вопрос: что я могу сделать, чтобы маркер не был анонимным?

4b9b3361

Ответ 1

Правильный способ аутентификации пользователя:

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

Ответ 3

В моем 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

Ответ 4

Я могу предложить другое решение (таким образом, он работает для меня). У меня есть собственный поставщик проверки подлинности со сложной логикой, и я не могу вообще использовать 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;
}

Ответ 5

У меня была такая же проблема и я нашел решение во время отладки. В зависимости от вашего хранилища сеансов вам может потребоваться изменить ваш файл 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;
}