Автоматическая проверка подлинности пользователя после регистрации
мы создаем бизнес-приложение с нуля в Symfony 2, и я столкнулся с небольшой проблемой с потоком регистрации пользователей: после того, как пользователь создает учетную запись, они должны автоматически войти в систему с этими учетными данными, а не быть немедленно вынуждены снова предоставить свои учетные данные.
У кого-нибудь был опыт с этим, или в состоянии указать мне в правильном направлении?
8 ответов:
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 параметра: сущность пользователя, учетные данные пользователя, имя брандмауэра, роли пользователей. Вам не нужно предоставлять учетные данные пользователя для маркер, чтобы быть действительным.Я не на 100% уверен, что установка маркера включена элемент
security.contextнеобходимо, если вы просто собираетесь перенаправить сразу. Но это, кажется, не больно, так что я оставил его.затем важная часть, устанавливающая переменную сеанса. Соглашение об именовании переменных -
_security_затем следует имя брандмауэра, в этом случаеmainделая_security_main
наконец-то понял это.
после регистрации пользователя, вы должны иметь доступ к объекту instanceof все, что вы установили в качестве объекта пользователя в конфигурации поставщика. Решение состоит в том, чтобы создать новый маркер с этой сущностью пользователя и передать его в контекст безопасности. Вот пример, основанный на моей настройке:
RegistrationController.php:$token = new UsernamePasswordToken($userEntity, null, 'main', array('ROLE_USER')); $this->get('security.context')->setToken($token);здесь
mainэто имя брандмауэра для вашего приложения (спасибо, @Joe). Это действительно все, что есть теперь система считает, что ваш пользователь полностью вошел в систему как пользователь, которого они только что создали.EDIT: в комментарии @Miquel я обновил образец кода контроллера, чтобы включить разумную роль по умолчанию для нового пользователя (хотя, очевидно, это можно настроить в соответствии с конкретными потребностями вашего приложения).
Если у вас есть объект 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 и мой опыт немного отличается от проблематично это, так что это комбинированная версия всей информации из этого вопроса плюс некоторые из моих собственных.
Я думаю Джо неверно о значении
$providerKeyтретий параметрUsernamePasswordTokenконструктор. Он должен быть ключом поставщика аутентификации (не пользователя). Он используется системой аутентификации для различения токенов, созданных для разных услуги поставщиков. Любой провайдер, который происходит от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. Кроме того, использование надлежащего поставщика будет означать, что события были обработаны для вас.
в случае, если у кого-то есть тот же следующий вопрос, который заставил меня вернуться сюда:
вызов
$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.). }нет необходимости отправлять событие, как я видел в других решениях.
inpired from FOS\UserBundle\Controller\RegistrationController:: authenticateUser
(от композитора.версия json FOSUserBundle: "friendsofsymfony / user-bundle": "~1.3")
Comments