php - after - ¿Cómo iniciar sesión/autenticar programáticamente a un usuario?
symfony security authentication token (3)
La versión aceptada no funcionará con Symfony 3.3. El usuario será autenticado en la próxima solicitud en lugar de la actual. El motivo es que ContextListener comprueba la existencia de una sesión previa y, si no existe, borrará la seguridad TokenStorage. La única forma de evitar esto (hackear como el infierno) es simular la existencia de la sesión anterior al inicializar manualmente la sesión (y la cookie) en la solicitud actual.
Avíseme si encuentra una mejor solución.
Por cierto, no estoy seguro de si esto debería fusionarse con la solución aceptada.
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);
}
El código anterior supone que su nombre de firewall (o nombre de contexto compartido) es common
.
Me gustaría ingresar al usuario justo después del proceso de registro, sin pasar por el formulario de inicio de sesión.
Es posible ? Encontré una solución con FOSUserBundle
, pero no la estoy usando en el proyecto en el que estoy trabajando.
Aquí está mi security.yml, estoy trabajando con dos firewalls. El codificador de texto plano es solo para probar.
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 }
Pruebe esto: para usuarios de Symfony 3 , no olvide hacer esta corrección para probar la igualdad de las contraseñas (ya que el método que se muestra para probar la contraseña en este enlace no funciona):
$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
Sí, puedes hacer esto a través de algo similar a lo siguiente:
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
}
}
El evento que se dispara al final no se realiza automáticamente cuando se establece un token en el contexto, mientras que normalmente se usa cuando se utiliza, por ejemplo, un formulario de inicio de sesión o similar. De ahí la razón para incluirlo aquí. Es posible que deba ajustar el tipo de token utilizado, según su caso de uso: UsernamePasswordToken
muestra arriba es un token central, pero puede usar otros si es necesario.
Editar : Ajustó el código anterior para explicar el parámetro ''público'' y también agregar los roles del usuario en la creación del token, según el comentario de Franco a continuación.