2012-07-12 44 views
19

我目前正在将2.0。*项目迁移到Symfony当前的2.1测试版。Symfony 2.1中的功能测试中的身份验证

在我的功能测试,我现在有这样的代码来创建一个客户端身份验证:

$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 \分量\安全\ HTTP \防火墙\ ContextListener” 中的方法 “onKernelResponse” 的。有这样的代码:

if ((null === $token = $this->context->getToken()) || ($token instanceof AnonymousToken)) { 
    $session->remove('_security_'.$this->contextKey); 
} else { 
    $session->set('_security_'.$this->contextKey, serialize($token)); 
} 

在我的情况下,如果“$令牌的instanceof AnonymousToken”是真实的,正因为如此会话密钥被删除。如果我注释掉代码,一切都按预期工作。

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

+0

我使用的是非常相似的片段,以你的登录特定功能测试用户。我也升级到了2.1,并且真的让我很开心,因为我的许多功能测试现在都失败了。 – 2012-08-07 06:05:38

+0

我发现在ContextListener.php中,ac所有的都是$ this-> context-> setToken(null),并且因为$ session === null而被调用?嗯... – 2012-08-07 06:44:22

+1

当我注释掉ContextListener.php:第77行 - $ this-> context-> setToken(null)时,我的测试完美无缺!所以也许这是一个线索! – 2012-08-07 06:49:11

回答

11

验证用户正确的方法是:

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

经过一番挖掘,我得出了同样的结论。但是这在我的测试中不起作用。无论如何感谢您的回答。 – smoove 2012-07-19 09:35:57

+0

您是否还删除了使用以下行开始的新会话:$ client-> getCookieJar() - > set(new \ Symfony \ Component \ BrowserKit \ Cookie(session_name(),true)); – 2012-07-19 09:59:03

+0

我尝试过,没有这条线,它不会改变任何东西。 – smoove 2012-07-19 10:20:03

1

在我的测试套件(工作于2.0和现在的2.1版本)中,我使用了扩展Symfony2 WebTestCase类的基类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

1

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

您需要创建专项行动这样

//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 } 

然后在测试只是给客户这个网址

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; 
} 
+0

这对我有用,而其他方法没有(使用Sf2.3) – caponica 2013-08-23 23:47:17

1

我有同样的问题,并找到了解决方案,同时调试。根据您的会话存储,您可能必须将cookie从session_name()更改为'MOCKSESSID'(如果您使用模拟会话,则使用该模式)我认为如果您在config_test.yml中有以下内容,它会自动更改为模拟会话存储:

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; 
}