カスタムログインには、次のコードのみが必要です。
$token = new UsernamePasswordToken($user, null, 'main', $user->getRoles());
$this->get("security.context")->setToken($token);
return $this->redirect($this->generateUrl('sonata_user_profile_show'));
これは、セキュリティコンテキストでUsernamePasswordTokenを設定することです。このトークン(およびユーザー)はシリアル化され、セッションに配置されます。次のページで、トークンはセッションからシリアル化されなくなり、これもシリアル化されていないユーザーが更新されます。
FOSUserBundleのユーザープロバイダーは、シリアル化されていないユーザーのIDを使用してこの更新を行います。
また、Doctrine2は、元のエンティティクラスではなくプロキシクラスをエンティティクラスとして使用する場合があります。このプロキシクラスは、複雑な遅延読み込みの複雑な実装によって、エンティティの「getId()」関数を上書きします。
これを合わせると、Doctrine2プロキシオブジェクトをUserPasswordTokenに入れると、シリアル化された後、シリアル化されていないプロキシオブジェクトの「getId()」が元のIDを返さないという事実につながる可能性があります。その場合、ユーザーはユーザープロバイダーによって更新できず、トークンは無効になります。
これに対する修正は、ユーザー名(または他の一意のプロパティ)を使用して更新することで「refreshUser()」を上書きするカスタムユーザープロバイダーを作成することです。
//...
class UserProvider extends FOSUserProvider
{
/**
* {@inheritDoc}
*/
public function refreshUser(SecurityUserInterface $user)
{
if (!$user instanceof User) {
throw new UnsupportedUserException(sprintf('Expected an instance of User, but got "%s".', get_class($user)));
}
if (null === $reloadedUser = $this->userManager->findUserBy(array('username' => $user->getUsername()))) {
throw new UsernameNotFoundException(sprintf('User with username "%s" could not be reloaded.', $user->getUsername()));
}
return $reloadedUser;
}
}