Je souhaite connecter l'utilisateur juste après le processus d'inscription, sans passer par le formulaire de connexion.
Est-ce possible ? J'ai trouvé une solution avec FOSUserBundle
, mais je ne l'utilise pas sur le projet sur lequel je travaille actuellement.
Voici mon security.yml, je travaille avec deux pare-feu. L'encodeur de texte brut est juste pour les tests.
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 }
Oui, vous pouvez le faire via quelque chose de similaire au suivant:
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
}
}
Le déclenchement de l'événement à la fin n'est pas automatiquement effectué lorsque vous placez un jeton dans le contexte, alors qu'il le serait normalement lors de l'utilisation, par exemple, d'un formulaire de connexion ou similaire. D'où la raison de l'inclure ici. Vous devrez peut-être ajuster le type de jeton utilisé, selon votre cas d'utilisation - le UsernamePasswordToken
illustré ci-dessus est un jeton de base, mais vous pouvez en utiliser d'autres si nécessaire.
Edit : Ajustement du code ci-dessus pour expliquer le paramètre 'public' et également ajouter les rôles de l'utilisateur dans la création du jeton, basé sur le commentaire de Franco ci-dessous .
La version acceptée ne fonctionnera pas avec symfony 3.3. L'utilisateur sera authentifié dans la prochaine requête au lieu de la requête actuelle. La raison en est que ContextListener vérifie l'existence de la session précédente et s'il n'existe pas, il effacera le TokenStorage de sécurité. Le seul moyen de contourner cela (hackish as hell) est de simuler l'existence de la session précédente en initialisant manuellement la session (et le cookie) sur la demande en cours.
Faites-moi savoir si vous trouvez une meilleure solution.
BTW Je ne sais pas si cela devrait être fusionné avec la solution acceptée.
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);
}
Le code ci-dessus suppose que votre nom de pare-feu (ou nom de contexte partagé) est common
.
Essayez ceci: Pour les utilisateurs de Symfony , n'oubliez pas de faire cette correction pour tester l'égalité des mots de passe (car la méthode indiquée pour tester le mot de passe sur ce lien ne fonctionne pas):
$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