Symfony 2.8 WebTestCase:無法創建登錄會話 (Symfony 2.8 WebTestCase: Cannot create logged-in session)


問題描述

Symfony 2.8 WebTestCase:無法創建登錄會話 (Symfony 2.8 WebTestCase: Cannot create logged‑in session)

我目前正在對基於 symfony 2.8 的管理區域進行單元測試。所以我為儀表板寫了一個小的基本測試:測試檢查

a)如果用戶當前沒有登錄,應該有一個重定向到登錄頁面。

b) 如果用戶已登錄,則應顯示儀表板。

為了“登錄”用戶(= 創建活動會話),我想出了一個基於在 symfony 文檔中的相應食譜文章中:How to Simulate Authentication with a Token in a Functional測試

但這似乎不起作用。我最初的測試失敗了。因此,我向僅打印出會話信息的虛擬控制器添加了另一個請求。這表明雖然似乎設置正確,但當前用戶信息和安全令牌存儲似乎不正確 ‑ 因為我得到默認的“AnonymousToken”和 getUser 方法的空返回。

這裡是我的測試代碼:

<?php

namespace GOC\Bundle\AdminBundle\Tests\Controller;

use FOS\RestBundle\Util\Codes;

use Symfony\Bundle\FrameworkBundle\Client;
use Symfony\Bundle\FrameworkBundle\Console\Application;
use Symfony\Component\BrowserKit\Cookie;
use Symfony\Component\Console\Input\ArrayInput;
use Symfony\Component\Console\Output\NullOutput;
use Symfony\Component\HttpFoundation\Session\Session;
use Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken;

use GOC\Bundle\FrameworkBundle\Model\ContextInterface;
use GOC\Bundle\FrameworkBundle\Tests\WebTestCase;

class DashboardControllerTest extends WebTestCase
{
    const BASE_URL = '';

    /**
     * @var ContextInterface|null
     */
    protected $context;

    public static function setUpBeforeClass()
    {
        $client = static::createClient([
            'environment' => 'test',
            'debug'       => false,
        ], [
            'HTTP_HOST' => 'demo‑cms.dev',
        ]);

        $container = $client‑>getContainer();
        $kernel    = $container‑>get('kernel');

        $application = new Application($kernel);
        $application‑>setAutoExit(false);

        $input = new ArrayInput(array(
            'command' => 'doctrine:mongodb:fixtures:load',
        ));
        $output = new NullOutput();
        $application‑>run($input, $output);
    }

    /**
     * Testing whether the backend is not publicly accessible
     */
    public function testFirewallRedirect()
    {
        $client = static::createClient();

        $client‑>request('GET', $this‑>buildUrl('/admin/dashboard'));
        $response = $client‑>getResponse();

        $this‑>assertTrue($client‑>getResponse()‑>isRedirect($this‑>buildUrl('http://localhost/admin/login')));

        $crawler  = $client‑>request('GET', $response‑>headers‑>get('location'));

        $this‑>assertEquals(
            1,
            $crawler‑>filter('html:contains("Willkommen")')‑>count()
        );
    }

    /**
     * Testing whether the backend is not publicly accessible
     */
    public function testFirewallAccess()
    {
        $client = static::createClient([
            'environment' => 'test',
            'debug'       => false,
        ], [
            'HTTP_HOST' => 'demo‑cms.dev',
        ]);

        $this‑>logIn($client);

        $client‑>request('GET', $this‑>buildUrl('/admin/dashboard'));
        $response = $client‑>getResponse();

        // This fails...
        //$this‑>assertEquals(Codes::HTTP_OK, $response‑>getStatusCode());

        // Debug statements
        $client‑>request('GET', $this‑>buildUrl('/forgot‑password‑sent'));
        $response = $client‑>getResponse();
        dump($response);
    }

    /**
     * @param Client $client
     */
    protected function logIn(Client $client)
    {
        $container = $client‑>getContainer();

        $repository = $container‑>get('goc_account.user_manager')‑>getRepository();
        $user       = $repository‑>getUserByUsername('admin@gardenofconcepts.com', $this‑>getContext($client));

        $firewall = 'main';
        $token    = new UsernamePasswordToken($user, null, $firewall, $user‑>getRoles());

        $container‑>get('security.token_storage')‑>setToken($token);
        $session = $container‑>get('session');

        // Saw this somewhere else, makes no difference though
        //$session = new Session(new MockArraySessionStorage());
        //$session‑>start();
        //$container‑>set('session', $session);


        $session‑>set('_security_'.$firewall, serialize($token));
        $session‑>save();

        $cookie = new Cookie($session‑>getName(), $session‑>getId());
        $client‑>getCookieJar()‑>set($cookie);
    }

    /**
     * @param $url
     *
     * @return string
     */
    protected function buildUrl($url)
    {
        return $this::BASE_URL . $url;
    }

    /**
     * @param Client $client
     *
     * @return ContextInterface
     */
    protected function getContext(Client $client)
    {
        if ($this‑>context) {

            return $this‑>context;
        }

        $this‑>context = $client‑>getContainer()‑>get('goc_framework.context_manager')‑>getContextByName('demo');

        return $this‑>context;
    }
}

提前感謝您的幫助 ‑ 非常感謝!


參考解法

方法 1:

We are not trying to mock the token but actually create one with the following function (which might be adaptable to your situation):

protected function createAuthenticatedClient($username, $password)
{
    $client = static::createClient();
    $client‑>request(
        'POST',
        '/api/v1/login_check',
        array(
            'username' => $username,
            'password' => $password,
        )
    );

    $data = json_decode($client‑>getResponse()‑>getContent(), true);

    $client = static::createClient();
    $client‑>setServerParameter('HTTP_Authorization', sprintf('Bearer %s', $data['token']));

    return $client;
}

After using this like

 $client = $this‑>createAuthenticatedClient('user', 'password');

every request sent will be attached with our actual Bearer.

(by JanLBA)

參考文件

  1. Symfony 2.8 WebTestCase: Cannot create logged‑in session (CC BY‑SA 2.5/3.0/4.0)

#authentication #PHP #symfony #unit-testing #session






相關問題

PHP Twitter OAuth - 我無法驗證我的帳戶 (PHP Twitter OAuth - I cannot authenticate my account)

如何設置 RIA 服務以使用現有的 ASP.Net 成員基礎 (How to setup RIA Services to use an existing ASP.Net membership base)

使用具有身份驗證的 URL 設置圖像-IOS SDK (Set Image With URL having authentication-IOS SDK)

支持 Facebook 的 Codeigniter 身份驗證庫 (Codeigniter Authentication library with Facebook support)

lighttpd:身份驗證後如何將端口(僅對本地主機可見)轉發到 WAN? (lighttpd: How to forward port (visible only to localhost) to WAN after authentication?)

Symfony 2.8 WebTestCase:無法創建登錄會話 (Symfony 2.8 WebTestCase: Cannot create logged-in session)

使用 facebook、twitter 等進行身份驗證。合而為一! (Authentication with facebook, twitter, etc.. all in one!)

默認情況下,ASP.NET 登錄控件是否使用 ReturnURL 進行重定向? (By default, does ASP.NET Login Control use the ReturnURL to redirect?)

發布/訂閱請求身份驗證作為服務(或通過服務密鑰)而不是 Auth0 臨時密鑰 (Pub/sub request authentication as a service (or by service key) instead of Auth0 temporary key)

通過 Nginx 進行 Haproxy 身份驗證 (Haproxy authentication through Nginx)

Django login() 身份驗證總是返回 None (Django login() authenticate always returns None)

laravel 微風 Multi Auth - 具有兩個不同註冊的 Admin Guard (laravel breeze Multi Auth - Admin Guard with two diffirent registration)







留言討論