2012-01-22 8 views
8

コントローラでRemember Me Cookieを手動で作成する方法を誰かが説明できますか?symfony2のcookieを手動で保存する(FOSUserBundle)

「登録」 ボタンを押した後にユーザーがログインしたままにしておきたい場合は、後でそのユーザーの資格情報でログインする必要はありません。

私は手動でクッキーを作成しようとしましたが、クッキーを推測しています 値が正しくないため、 "remember me"機能 は機能しません。 正しい名前のクッキーが設定されます。私はそれをチェックした。

Remember me機能は、ユーザーの資格情報で通常の ログイン手順を使用する場合に、正常に機能します。

のsecurity.yml は、クッキーが設定されていても、これは私が今持っているものである私

security: 
    firewalls: 
     main: 
      remember_me: 
       lifetime: 86400 
       domain: ~ 
       path: /
       key:  myKey 

に覚えのsecurity.yml、それは動作しません。

$um = $this->get('fos_user.user_manager'); 
$member = $um->createUser(); 

… Form stuff with bindRequest etc. 

$um->updatePassword($member); 
$um->updateUser($member); 

$providerKey = $this->container->getParameter('fos_user.firewall_name'); 
$securityKey = 'myKey'; 

$token = new RememberMeToken($member, $providerKey, $securityKey, 
$member->getRoles()); 
$this->container->get('security.context')->setToken($token); 

$redirectResponse = new RedirectResponse($url); 
$redirectResponse->headers->setCookie(
    new \Symfony\Component\HttpFoundation\Cookie(
     'REMEMBERME', 
     base64_encode(implode(':', array($member->getUsername(), 
$member->getPassword()))), 
     time() + 60*60*24 
    ) 
); 
return $redirectResponse; 

更新:

また、私は反射で PersistentTokenBasedRememberMeServicesクラスで作業しようとしましたが、それは動作しません。クッキーが設定されますが、私がのSymfony v2.0.5とFOSUserBundleを使用してい

$token = $this->container->get('security.context')->getToken(); 

$providerKey = $this->container->getParameter('fos_user.firewall_name'); 
$securityKey = 'myKey'; 

$persistenService = new 
PersistentTokenBasedRememberMeServices(array($um), $providerKey, 
$securityKey, array('path' => '/', 'name' => 'REMEMBERME', 'domain' => 
null, 'secure' => false, 'httponly' => true, 
'lifetime' => 86400)); 
$persistenService->setTokenProvider(new InMemoryTokenProvider()); 

$method = new \ReflectionMethod('Symfony\Component\Security\Http\RememberMe\PersistentTokenBasedRememberMeServices', 
'onLoginSuccess'); 
$method->setAccessible(true); 
$method->invoke($persistenService, $request, $redirectResponse, $token); 

を働いていない1.0

UPDATE 2:私は、第三の方法を試してみた

。反射を超えるがない場合と同じ:

$token = $this->container->get('security.context')->getToken(); 

$providerKey = $this->container->getParameter('fos_user.firewall_name'); 
$securityKey = 'myKey'; 

$persistenService = new PersistentTokenBasedRememberMeServices(array($um), $providerKey, $securityKey, array('path' => '/', 'name' => 'REMEMBERME', 'domain' => null, 'secure' => false, 'httponly' => true, 'lifetime' => 31536000, 'always_remember_me' => true, 'remember_me_parameter' => '_remember_me')); 
$persistenService->setTokenProvider(new InMemoryTokenProvider()); 

$persistenService->loginSuccess($request, $redirectResponse, $token); 

答えて

10

あなたが直接リメンバー・ミークッキーを設定している場合は、次の形式を使用する必要があります。

sha256(<classname> . <username> . <expiry-timestamp> . <password> . <key>) 
:ハッシュはなり

base64_encode(<classname>:base64_encode(<username>):<expiry-timestamp>:<hash>) 

鍵は、remember_meセクションのセキュリティ(.xml/.yml)に入力した鍵です。

これはのSymfony /コンポーネント/セキュリティ/ HTTP /リメンバー・ミー/ TokenBasedRememberMeService.phpファイルにprocessAutoLoginCookie()方法から取得されます。

これはすべて同じクラスのgenerateCookieValue()メソッドで行われます。

しかし、このように直接使用することはお勧めしませんが、TokenBasedRememberMeService::onLoginSuccess()メソッドを呼び出すことができますか?コードをより堅牢で移植性のあるものにするためにこのクッキーを設定してください。

12

ここで私はそれをしました。私はFOSUserBundleを使用していませんし、Doctrine Entity User Providerを使用していますが、ニーズに合わせるのは簡単です。ここでは一般的なソリューションです。

// after registration and persisting the user object to DB, I'm logging the user in automatically 
$token = new UsernamePasswordToken($user, null, 'main', $user->getRoles()); 

// but you can also get the token directly, if you're user is already logged in 
$token = $this->container->get('security.context')->getToken(); 

// write cookie for persistent session storing 
$providerKey = 'main'; // defined in security.yml 
$securityKey = 'MySecret'; // defined in security.yml 

$userProvider = new EntityUserProvider($this->getDoctrine()->getEntityManager(), 'MyCompany\MyBundle\Entity\User', 'username'); 

$rememberMeService = new TokenBasedRememberMeServices(array($userProvider), $securityKey, $providerKey, array(
       'path' => '/', 
       'name' => 'MyRememberMeCookie', 
       'domain' => null, 
       'secure' => false, 
       'httponly' => true, 
       'lifetime' => 1209600, // 14 days 
       'always_remember_me' => true, 
       'remember_me_parameter' => '_remember_me') 
      ); 

$response = new Response(); 
$rememberMeService->loginSuccess($request, $response, $token); 

// further modify the response 
// ........ 

return $response; 

はちょうどあなたが(私は上記のコードでやったように)trueにを設定するか、何らかの方法であなたの$ _POSTパラメータでそれを持っている必要があります覚えて、それ以外の方法はAbstractRememberMeServicesisRememberMeRequestedはfalseを返し、クッキーは保存されません。

あなたは(第三の試みで)あなたは間違っていた何:)しかし、正しい解にかなり接近していたが、ここでのパラメータの順序を変更したということです。

$persistenService = new PersistentTokenBasedRememberMeServices(array($um), $providerKey, $securityKey, array('path' => '/', 'name' => 'REMEMBERME', 'domain' => null, 'secure' => false, 'httponly' => true, 'lifetime' => 31536000, 'always_remember_me' => true, 'remember_me_parameter' => '_remember_me')); 

は中__construct()を見てみましょうAbstractRememberMeServices.php。 )$securityKeyを2番目の引数に、$providerKeyを3番目の引数に渡す必要があります。間違った方法ではありません。

私がまだ分かっていないのは、security.ymlのパラメータを直接コントローラーはそれを複製しないでください。 $this->container->getParameter()を使用すると、config.ymlにparametersキーの下に保存されたパラメータを取得できますが、設定ツリーの上位にはパラメータがありません。これについての考えは?

+1

をベースとした上で、生の手続きを投稿するには、parameters.ymlにし、セキュリティに入れなければなりません.ymlは%your_parameter_name%でそれらを呼び出します。セキュリティとパラメータで利用できるようになりました – guillaumepotier

+3

+1このためにSymfony2のセキュリティクラスを使用しています。 remember-me cookieのデフォルトのcookie名は 'REMEMBERME'です。ファイアウォールと同じCookie名を使用する場合のみ、手動で設定されたCookieに対して認証されますが、セキュリティリスナーによって認識されます。 – flu

+1

引数1をSymfony \ Bridge \ Doctrine \ Security \ User \ EntityUserProvider :: __ construct()に渡すと、Doctrine \ Common \ Persistence \ ManagerRegistryインターフェイスが実装されていなければなりません。D: –

0

私にとって最も簡単な解決策はBaseTokenBasedRememberMeServicesを拡張し、それが

namespace AppBundke\Security\Http; 
use Symfony\Component\HttpFoundation\Cookie; 
use Symfony\Component\Security\Http\RememberMe\TokenBasedRememberMeServices as BaseTokenBasedRememberMeServices; 


class TokenBasedRememberMeServices extends BaseTokenBasedRememberMeServices 
{ 
    protected $options_new = array('name' => 'REMEMBERME', 'domain' => null, 'path' => '/'); 

    public function __construct($userProvider, $secret, $providerKey, array $options = array(), LoggerInterface $logger = null) 
    { 
      return parent::__construct(array($userProvider), $secret, $providerKey, array_merge($this->options_new, $options)); 
    } 

    public function generateCookie($user, $username, $expires, $password) 
    { 
     $cookie = new Cookie(
      $this->options['name'], 
      parent::generateCookieValue(get_class($user), $username, $expires, $password), 
      $expires, 
      $this->options['path'], 
      $this->options['domain'], 
      $this->options['secure'], 
      $this->options['httponly'] 
     ); 
    return $cookie; 
    } 
} 

とコントローラでの取り扱い聞かせていました。

$user = $this->getUser(); 
$providerKey = $this->getParameter('fos_user.firewall_name'); 
$secret = $this->getParameter('secret'); 
$cookie_life_time = $this->getParameter('cookie_life_time'); 

$remember_me_service = new TokenBasedRememberMeServices($user, $secret, $providerKey); 
$remember_me_cookie = $remember_me_service->generateCookie($user, $user->getUsername(),(time() + $cookie_life_time), $user->getPassword()); 

レスポンス私はトークンによって、接続後にユーザーをリメンバー・ミークッキーを設定しようとしたとき、私は同じ問題を持っています。2.

0

とその作品を願っています$ remember_me_cookie

に設定されたCookie、 Guard Authenticationを使用してください。

この場合、$ response-> headers-> setCookie()を使用できるレスポンスオブジェクトがなく、setcookie()を使用する必要があります。 この場合、RedirectResponseを作成するのは適切ではありません。

これは、リファクタリングする必要がありますが、私は、私は重複を避けるためのsecurity.ymlでクッキーのパラメータを取得するための私のサービス

$expires = time() + 2628000; 
$hash = hash_hmac(
    'sha256', 
    get_class($user).$user->getUsername().$expires.$user->getPassword(), 'secret in parameters.yml' 
); 
$value = base64_encode(implode(':', [get_class($user), base64_encode($user->getUsername()), $expires, $hash])); 
setcookie(
    'REMEMBERME', 
    $value, 
    $expires, 
    '/', 
    'host', 
    'ssl boolean', 
    true 
); 
関連する問題