Я хотел бы зарегистрировать пользователя сразу после процесса регистрации, не пропуская регистрационную форму.
Возможно ли это? Я нашел решение с 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
}
}
Запуск события в конце не выполняется автоматически, когда вы устанавливаете токен в контекст, тогда как это обычно происходит при использовании, например, формы входа или аналогичного. Отсюда и причина включения его здесь. Вам может потребоваться настроить тип используемого токена, в зависимости от вашего варианта использования - показанный выше UsernamePasswordToken
является основным токеном, но при необходимости вы можете использовать другие.
Изменить. Скорректированный выше код, чтобы объяснить параметр "public", а также добавить роли пользователя в создание маркера на основе комментария Franco ниже.
Принятая версия не будет работать с symfony 3.3. Пользователь будет аутентифицирован в следующем запросе вместо текущего. Причина в том, что ContextListener проверяет существование предыдущего сеанса, и если он не существует, он очистит защиту TokenStorage. Единственный путь вокруг этого (хакерский, как ад) - подделка существования предыдущего сеанса, вручную инициализируя сеанс (и cookie) по текущему запросу.
Сообщите мне, если вы найдете лучшее решение.
Кстати, я не уверен, что это должно быть объединено с принятым решением.
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
.
form_login: require_previous_session: false
Попробуйте следующее: Для пользователей 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