Я хотел бы зарегистрировать пользователя сразу после процесса регистрации, не пропуская регистрационную форму.
Это возможно ? Я нашел решение с FOSUserBundle
, но я не использую его в проекте, над которым я действительно работаю.
Вот мой security.yml, я работаю с двумя брандмауэрами. Кодировщик простого текста предназначен только для тестирования.
security: encoders: Symfony\Component\Security\Core\User\User: plaintext Ray\CentralBundle\Entity\Client: md5 role_hierarchy: ROLE_ADMIN: ROLE_USER ROLE_SUPER_ADMIN: [ROLE_USER, ROLE_ADMIN, ROLE_ALLOWED_TO_SWITCH] providers: in_memory: users: admin: { password: admin, roles: [ 'ROLE_ADMIN' ] } entity: entity: { class: Ray\CentralBundle\Entity\Client, property: email } firewalls: dev: pattern: ^/(_(profiler|wdt)|css|images|js)/ security: false user_login: pattern: ^/user/login$ anonymous: ~ admin_login: pattern: ^/admin/login$ anonymous: ~ admin: pattern: ^/admin provider: in_memory form_login: check_path: /admin/login/process login_path: /admin/login default_target_path: /admin/dashboard logout: path: /admin/logout target: / site: pattern: ^/ provider: entity anonymous: ~ form_login: check_path: /user/login/process login_path: /user/login default_target_path: /user logout: path: /user/logout target: / access_control: - { path: ^/user/login, roles: IS_AUTHENTICATED_ANONYMOUSLY } - { path: ^/admin/login, roles: IS_AUTHENTICATED_ANONYMOUSLY } - { path: ^/user, roles: ROLE_USER } - { path: ^/admin, roles: ROLE_ADMIN } - { path: ^/, roles: IS_AUTHENTICATED_ANONYMOUSLY }
Да, вы можете сделать это через что-то похожее на следующее:
use Symfony\Component\EventDispatcher\EventDispatcher, Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken, Symfony\Component\Security\Http\Event\InteractiveLoginEvent; public function registerAction() { // ... if ($this->get("request")->getMethod() == "POST") { // ... Do any password setting here etc $em->persist($user); $em->flush(); // Here, "public" is the name of the firewall in your security.yml $token = new UsernamePasswordToken($user, $user->getPassword(), "public", $user->getRoles()); // For older versions of Symfony, use security.context here $this->get("security.token_storage")->setToken($token); // Fire the login event // Logging the user in above the way we do it doesn't do this automatically $event = new InteractiveLoginEvent($request, $token); $this->get("event_dispatcher")->dispatch("security.interactive_login", $event); // maybe redirect out here } }
Запуск события в конце не выполняется автоматически, когда вы устанавливаете токен в контекст, тогда как это обычно происходит при использовании, например, формы входа или подобного. Отсюда и причина включения его здесь. Вам может потребоваться настроить тип используемого токена, в зависимости от вашего варианта использования – показанный выше UserPasswordToken является основным токеном, но при необходимости вы можете использовать другие.
Изменить : отредактировал приведенный выше код, чтобы объяснить параметр «общедоступный», а также добавить роли пользователя в создание маркера на основе комментария Франко ниже.
Принятая версия не будет работать с symfony 3.3. Пользователь будет аутентифицирован в следующем запросе вместо текущего. Причина в том, что ContextListener проверяет существование предыдущего сеанса, и если он не существует, он очистит защиту TokenStorage. Единственный путь вокруг этого (хакерский, как ад) – подделка существования предыдущего сеанса, вручную инициализируя сеанс (и cookie) в текущем запросе.
Дайте мне знать, если вы найдете лучшее решение.
BTW Я не уверен, что это должно быть объединено с принятым решением.
private function logUserIn(User $user) { $token = new UsernamePasswordToken($user, null, "common", $user->getRoles()); $request = $this->requestStack->getMasterRequest(); if (!$request->hasPreviousSession()) { $request->setSession($this->session); $request->getSession()->start(); $request->cookies->set($request->getSession()->getName(), $request->getSession()->getId()); } $this->tokenStorage->setToken($token); $this->session->set('_security_common', serialize($token)); $event = new InteractiveLoginEvent($this->requestStack->getMasterRequest(), $token); $this->eventDispatcher->dispatch("security.interactive_login", $event); }
В приведенном выше коде предполагается, что ваше имя брандмауэра (или общее имя контекста) является common
.
Попробуйте следующее: для пользователей Symfony 3 не забудьте сделать это исправление, чтобы проверить равенство паролей (поскольку метод, показанный для проверки пароля по этой ссылке, не работает):
$current_password = $user->getPassword(); $user_entry_password = '_got_from_a_form'; $factory = $this->get('security.encoder_factory'); $encoder = $factory->getEncoder($user); $password = $encoder->encodePassword($user_entry_password, $user->getSalt()); if(hash_equals($current_password, $password)){ //Continue there } // I hash the equality process for more security
+ info: hash_equals_function