私たちはSymfony2でゼロからビジネスアプリを構築していますが、ユーザー登録フローに少し問題がありました。ユーザーがアカウントを作成した後、代わりにそれらのクレデンシャルで自動的にログインする必要があります。すぐに再び資格情報を提供することを余儀なくされます。
誰かがこれを経験したことがありますか、または私を正しい方向に向けることができましたか?
私たちはSymfony2でゼロからビジネスアプリを構築していますが、ユーザー登録フローに少し問題がありました。ユーザーがアカウントを作成した後、代わりにそれらのクレデンシャルで自動的にログインする必要があります。すぐに再び資格情報を提供することを余儀なくされます。
誰かがこれを経験したことがありますか、または私を正しい方向に向けることができましたか?
Symfony 4.0
このプロセスはSymfony3から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
、下位互換性があるように作成されているため、引き続き使用できます。Symfony3用にアップデートする準備をしてください。
セキュリティのための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
ます。
最後に、これを理解しました。
ユーザー登録後、プロバイダー構成でユーザーエンティティとして設定したオブジェクトインスタンスにアクセスできるようになります。解決策は、そのユーザーエンティティで新しいトークンを作成し、それをセキュリティコンテキストに渡すことです。これが私の設定に基づく例です:
RegistrationController.php:
$token = new UsernamePasswordToken($userEntity, null, 'main', array('ROLE_USER'));
$this->get('security.context')->setToken($token);
アプリケーションのファイアウォールの名前はどこmain
にありますか(ありがとう、@ Joe)。本当にこれですべてです。これで、システムは、完全にログインしたユーザーを、作成したばかりのユーザーと見なします。
編集:@Miquelのコメントに従って、コントローラーのコードサンプルを更新して、新しいユーザーに適したデフォルトの役割を追加しました(ただし、これはアプリケーションの特定のニーズに応じて調整できます)。
UserInterfaceオブジェクトがある場合(ほとんどの場合そうなるはずです)、最後の引数に実装されているgetRoles関数を使用することをお勧めします。したがって、関数logUserを作成すると、次のようになります。
public function logUser(UserInterface $user) {
$token = new UsernamePasswordToken($user, null, 'main', $user->getRoles());
$this->container->get('security.context')->setToken($token);
}
私はSymfony2.2を使用していますが、私の経験はProblematicのものとは少し異なっていたので、これはこの質問のすべての情報と私自身の情報を組み合わせたものです。
Joeは、コンストラクター$providerKey
の3番目のパラメーターであるの値について間違っていると思います。UsernamePasswordToken
これは、認証(ユーザーではない)プロバイダーのキーであると想定されています。これは、認証システムによって、さまざまなプロバイダー用に作成されたトークンを区別するために使用されます。子孫のプロバイダーUserAuthenticationProvider
は、プロバイダーキーが自身のプロバイダーキーと一致するトークンのみを認証します。たとえば、は、UsernamePasswordFormAuthenticationListener
作成するトークンのキーを、対応するのキーと一致するように設定しますDaoAuthenticationProvider
。これにより、1つのファイアウォールに、互いに踏み込むことなく、複数のユーザー名とパスワードのプロバイダーを含めることができます。したがって、他のプロバイダーと競合しないキーを選択する必要があります。私は使用します'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'
誰かが同じ後続の質問をして、私がここに戻ってきた場合:
呼び出し
$this->container->get('security.context')->setToken($token);
security.context
使用されるルートの電流にのみ影響します。
つまり、ファイアウォールの制御内のURLからのみユーザーにログインできます。
(必要に応じてルートの例外を追加します- IS_AUTHENTICATED_ANONYMOUSLY
)
ここですでに問題となっているように、このとらえどころのない$ ProviderKeyパラメーターは、実際にはファイアウォールルールの名前(以下の例の場合は「foobar」)にすぎません。
firewalls:
foobar:
pattern: /foo/
私はここですべての答えを試しましたが、どれもうまくいきませんでした。コントローラでユーザーを認証できる唯一の方法は、サブリクエストを作成してからリダイレクトすることです。これが私のコードです。私は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")