2012-07-12 105 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; 
}