回答:
symfony 4.0
このプロセスはsymfony 3から4に変更されていませんが、新しく推奨されたAbstractControllerを使用した例を次に示します。security.token_storage
とsession
サービスの両方が親getSubscribedServices
メソッドに登録されているので、それらをコントローラーに追加する必要はありません。
use Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use YourNameSpace\UserBundle\Entity\User;
class LoginController extends AbstractController{
public function registerAction()
{
$user = //Handle getting or creating the user entity likely with a posted form
$token = new UsernamePasswordToken($user, null, 'main', $user->getRoles());
$this->container->get('security.token_storage')->setToken($token);
$this->container->get('session')->set('_security_main', serialize($token));
// The user is now logged in, you can redirect or do whatever.
}
}
Symfony 2.6.x-Symfony 3.0.x
symfony 2.6の時点でsecurity.context
非推奨になりましたsecurity.token_storage
。これでコントローラーは次のようになります。
use Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use YourNameSpace\UserBundle\Entity\User;
class LoginController extends Controller{
public function registerAction()
{
$user = //Handle getting or creating the user entity likely with a posted form
$token = new UsernamePasswordToken($user, null, 'main', $user->getRoles());
$this->get('security.token_storage')->setToken($token);
$this->get('session')->set('_security_main', serialize($token));
}
}
これは非推奨ですがsecurity.context
、下位互換性が確保されているため、引き続き使用できます。Symfony 3用に更新する準備をしてください
セキュリティのための2.6の変更について詳しくは、https: //github.com/symfony/symfony/blob/2.6/UPGRADE-2.6.mdを参照してください。
symfony 2.3.x
symfony 2.3でこれを達成するために、もはやセキュリティコンテキストでトークンを設定することはできません。トークンをセッションに保存する必要もあります。
次のようなファイアウォールを備えたセキュリティファイルを想定します。
// app/config/security.yml
security:
firewalls:
main:
//firewall settings here
そして、同様のコントローラーアクション:
use Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use YourNameSpace\UserBundle\Entity\User;
class LoginController extends Controller{
public function registerAction()
{
$user = //Handle getting or creating the user entity likely with a posted form
$token = new UsernamePasswordToken($user, null, 'main', $user->getRoles());
$this->get('security.context')->setToken($token);
$this->get('session')->set('_security_main',serialize($token));
//Now you can redirect where ever you need and the user will be logged in
}
}
トークンを作成するにはUsernamePasswordToken
、を作成します。これは、4つのパラメーターを受け入れます:ユーザーエンティティ、ユーザー資格情報、ファイアウォール名、ユーザーロール。トークンを有効にするためにユーザー資格情報を提供する必要はありません。
security.context
すぐにリダイレクトする場合は、トークンをに設定する必要があることを100%確信していません。しかし、それは痛くないようですので、私はそれを残しました。
次に重要な部分は、セッション変数を設定することです。変数の命名規則の_security_
後にファイアウォール名が続きます。この場合main
、_security_main
$this->get('session')->set('_security_main', serialize($token));
。@Chausserありがとうございます!
main
、あなたが名前の別のファイアウォールで認証されているadmin
(あなたがユーザーを偽装しているとして)、奇妙なことが起こります:_security_admin
取得UsernamePasswordToken
あなたが提供されたユーザーで、つまりあなたがから「切断」を取得しますあなたのadmin
ファイアウォール。「admin」ファイアウォールのトークンを維持する方法はありますか?
setToken(..)
下で、またはまだ認証されていない状態で呼び出した場合にのみ機能します。
最後にこれを考え出した。
ユーザー登録後、プロバイダー設定でユーザーエンティティとして設定したもののオブジェクトインスタンスにアクセスできるはずです。解決策は、そのユーザーエンティティで新しいトークンを作成し、それをセキュリティコンテキストに渡すことです。これは私のセットアップに基づく例です:
RegistrationController.php:
$token = new UsernamePasswordToken($userEntity, null, 'main', array('ROLE_USER'));
$this->get('security.context')->setToken($token);
main
アプリケーションのファイアウォールの名前はどこですか(ありがとう、@ Joe)。それだけです。システムは、完全にログインしたユーザーを、作成したばかりのユーザーと見なします。
編集:@Miquelのコメントに従って、コントローラーコードサンプルを更新して、新しいユーザーに適切なデフォルトの役割を含めました(ただし、これはアプリケーションの特定のニーズに応じて調整できます)。
use Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken;
UserInterfaceオブジェクトがある場合(ほとんどの場合そうなります)、最後の引数に実装するgetRoles関数を使用することをお勧めします。したがって、関数logUserを作成すると、次のようになります。
public function logUser(UserInterface $user) {
$token = new UsernamePasswordToken($user, null, 'main', $user->getRoles());
$this->container->get('security.context')->setToken($token);
}
私はSymfony 2.2を使用していて、私の経験はProblematicのそれとは少し異なっていたので、これはこの質問のすべての情報といくつかの情報を組み合わせたバージョンです。
Joeは$providerKey
、UsernamePasswordToken
コンストラクタの3番目のパラメータであるの値について間違っていると思います。これは、(ユーザーではなく)認証プロバイダーのキーとなるはずです。認証システムは、さまざまなプロバイダー用に作成されたトークンを区別するために使用されます。子孫のプロバイダーはUserAuthenticationProvider
、プロバイダーキーが自身のトークンと一致するトークンのみを認証します。たとえば、はUsernamePasswordFormAuthenticationListener
作成するトークンのキーを、対応するのキーと一致するように設定しますDaoAuthenticationProvider
。これにより、単一のファイアウォールが複数のユーザー名+パスワードプロバイダーを使用して、それらが互いに踏み込むことがなくなります。したがって、他のプロバイダーと競合しないキーを選択する必要があります。使用します'new_user'
。
アプリケーションの他の部分に、認証成功イベントに依存するシステムがいくつかあります。これは、コンテキストにトークンを設定するだけでは起動されません。EventDispatcher
コンテナーからを取得し、イベントを手動で起動する必要がありました。明示的なログインリクエストに応答するのではなく、暗黙的にユーザーを認証しているため、インタラクティブログインイベントも発生させないことにしました。
use Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken;
use Symfony\Component\Security\Core\AuthenticationEvents;
use Symfony\Component\Security\Core\Event\AuthenticationEvent;
$user = // get a Symfony user instance somehow
$token = new UsernamePasswordToken(
$user, null, 'new_user', $user->getRoles() );
$this->get( 'security.context' )->setToken( $token );
$this->get( 'event_dispatcher' )->dispatch(
AuthenticationEvents::AUTHENTICATION_SUCCESS,
new AuthenticationEvent( $token ) );
の使用で$this->get( .. )
は、スニペットがコントローラーメソッド内にあると想定しています。別の場所でコードを使用ContainerInterface::get( ... )
している場合は、環境に適した方法で呼び出すようにコードを変更する必要があります。たまたま私のユーザーエンティティは実装されているUserInterface
ので、トークンで直接使用できます。そうでない場合は、UserInterface
インスタンスに変換する方法を見つける必要があります。
そのコードは機能しますが、Symfonyの認証アーキテクチャを操作するのではなく、ハッキングしているように感じます。をハイジャックするよりも、独自のトークンクラスを使用して新しい認証プロバイダーを実装する方がおそらく正しいでしょうUsernamePasswordToken
。また、適切なプロバイダーを使用すると、イベントが処理されます。
Symfony 4.4では、コントローラーメソッドで次のことを簡単に実行できます(Symfonyのドキュメントから参照:https : //symfony.com/doc/current/security/guard_authentication.html#manually-authenticating-a-user):
// src/Controller/RegistrationController.php
// ...
use App\Security\LoginFormAuthenticator;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Security\Guard\GuardAuthenticatorHandler;
class RegistrationController extends AbstractController
{
public function register(LoginFormAuthenticator $authenticator, GuardAuthenticatorHandler $guardHandler, Request $request)
{
// ...
// after validating the user and saving them to the database
// authenticate the user and use onAuthenticationSuccess on the authenticator
return $guardHandler->authenticateUserAndHandleSuccess(
$user, // the User object you just created
$request,
$authenticator, // authenticator whose onAuthenticationSuccess you want to use
'main' // the name of your firewall in security.yaml
);
}
}
重要なことの1つは、ファイアウォールがに設定されていないことを確認してくださいlazy
。その場合、トークンはセッションに保存されず、ログインすることもありません。
firewalls:
main:
anonymous: ~ # this and not 'lazy'
すでにここで問題となっているように、このわかりにくい$ providerKeyパラメータは実際にはファイアウォールルールの名前にすぎません。以下の例の場合は「foobar」です。
firewalls:
foobar:
pattern: /foo/
blablabla
3番目のパラメータとしてUsernamePasswordToken に渡しても機能する理由を教えてください。このパラメータの意味は何ですか?
ここですべての答えを試しましたが、どれもうまくいきませんでした。コントローラでユーザーを認証できる唯一の方法は、サブリクエストを作成してからリダイレクトすることです。これが私のコードです、私はsilexを使用していますが、symfony2に簡単に適応できます:
$subRequest = Request::create($app['url_generator']->generate('login_check'), 'POST', array('_username' => $email, '_password' => $password, $request->cookies->all(), array(), $request->server->all());
$response = $app->handle($subRequest, HttpKernelInterface::MASTER_REQUEST, false);
return $app->redirect($app['url_generator']->generate('curriculos.editar'));
Symfonyバージョン2.8.11(おそらく古いバージョンと新しいバージョンで動作します)で、FOSUserBundleを使用する場合は、次のようにします。
try {
$this->container->get('fos_user.security.login_manager')->loginUser(
$this->container->getParameter('fos_user.firewall_name'), $user, null);
} catch (AccountStatusException $ex) {
// We simply do not authenticate users which do not pass the user
// checker (not enabled, expired, etc.).
}
他のソリューションで見たように、イベントをディスパッチする必要はありません。
FOS \ UserBundle \ Controller \ RegistrationController :: authenticateUserから作成
(composer.json FOSUserBundleバージョンから: "friendsofsymfony / user-bundle": "〜1.3")