首页 文章

Symfony 2.1中的功能测试中的身份验证

提问于
浏览
19

我目前正在将2.0 . *项目迁移到Symfony的当前2.1 beta版 .

在我的功能测试中,我目前使用此代码来创建具有身份验证的客户端:

$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中没有,数据没有在会话中设置 .

有任何想法吗?

Edit (adding more info):

似乎问题在于文件“ Symfony\Component\Security\Http\Firewall\ContextListener " in the method " 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”是真的,因此会话密钥被删除 . 如果我注释掉那些代码,一切都按预期工作 .

所以我想我的新问题是:我能做些什么来使令牌不是匿名的?

5 回答

  • 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();
    
  • 11

    我已经记录了一张票:https://github.com/symfony/symfony/issues/3287

    Symfony 2.1 RC似乎存在问题 .

  • 1

    在我的testsuite(使用2.0和现在的2.1)中,我使用扩展Symfony2 WebTestCase类的Base类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,
        ));
    }
    

    然后,在我的Test类中,我使用:

    $client = static::createClient();
    

    创建一个匿名客户端和

    $client = static::createAuthClient('user','pass');
    

    创建一个经过身份验证的人 .

    这就像2.1上的魅力

  • 1

    我可以建议另一个解决方案(因此它对我有用) . 我有一个自定义身份验证提供程序,具有复杂的逻辑,我根本无法使用http_basic机制 .

    您需要像这样创建特殊的Action

    //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;
    }
    
  • 1

    我有同样的问题,并在调试时找到了解决方案 . 根据您的会话存储,您可能必须将您的cookie从session_name()更改为'MOCKSESSID'(如果您使用模拟会话时使用它 . 我想如果您在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;
    }
    

相关问题