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

有任何想法吗?

编辑(添加更多信息):

似乎问题出在方法“ onKernelResponse ”中的文件“ Symfony\Component\Security\Http\Firewall\ContextListener ”中。有这个代码:

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”为真,因此会话密钥被删除。如果我注释掉该代码,一切都会按预期工作。

所以我想我的新问题是:我该怎么做才能使令牌不匿名?

4

5 回答 5

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();
于 2012-07-19T09:22:06.967 回答
1

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

Symfony 2.1 RC 似乎存在一个问题。

于 2012-08-07T11:52:39.083 回答
1

i had the same issue and found a solution while debugging. Depending on your Session Storage, you might have to change your cookie from session_name() to 'MOCKSESSID' (which is used if your using the mock session. I think if you have the following in your config_test.yml it is automatically changed to Mock Session Storage:

framework:
   test: ~

For completeness, here my full code (i'm using 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;
}
于 2012-12-26T19:43:46.197 回答
1

在我的测试套件中(在 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,
    ));
}

然后,在我的测试课程中,我使用:

    $client = static::createClient();

创建一个匿名客户和

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

创建一个经过身份验证的。

这在 2.1 上就像一个魅力

于 2012-08-11T21:13:10.067 回答
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 }

然后在测试中将客户端发送到这个 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;
}
于 2012-09-19T11:59:47.487 回答