Automatyczne uwierzytelnianie użytkowników po rejestracji

Budujemy aplikację biznesową od podstaw w Symfony 2 i napotkałem mały problem z rejestracją użytkowników: po utworzeniu konta Użytkownik powinien być automatycznie zalogowany za pomocą tych poświadczeń, zamiast być natychmiast zmuszony do ponownego podania swoich poświadczeń.

Ktoś miał z tym jakieś doświadczenie, albo był w stanie wskazać mi właściwy kierunek?

Author: Shandhanu Mohan, 2011-05-04

8 answers

Symfony 4.0

Ten proces nie zmienił się z symfony 3 na 4, ale oto przykład użycia nowo zalecanego kontrolera AbstractController. Zarówno usługi security.token_storage, jak i session są zarejestrowane w metodzie nadrzędnej getSubscribedServices, więc nie musisz dodawać ich do kontrolera.

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

Nie jest to jednak możliwe, ponieważ nie jest to możliwe. Kontrolerem może być teraz po prostu:
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));
    }

}

Podczas gdy to jest przestarzałe możesz nadal używać security.context, ponieważ została ona dostosowana do wstecznej kompatybilności. Po prostu przygotuj się na aktualizację Symfony 3

Możesz przeczytać więcej o zmianach 2.6 Dla Bezpieczeństwa tutaj: https://github.com/symfony/symfony/blob/2.6/UPGRADE-2.6.md

Symfony 2.3.x

Aby to osiągnąć w symfony 2.3 nie można już ustawiać tokena w kontekście bezpieczeństwa. Musisz również zapisać token na sesji.

Zakładając zabezpieczenie Plik z zaporą typu:

// app/config/security.yml
security:
    firewalls:
        main:
            //firewall settings here

I podobne działanie kontrolera:

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
    }

}

Aby utworzyć token, który chcesz utworzyć UsernamePasswordToken, przyjmuje on 4 parametry: jednostkę użytkownika, poświadczenia użytkownika, nazwę zapory sieciowej, role użytkownika. Nie musisz podawać danych uwierzytelniających użytkownika, aby token był ważny.

Nie jestem w 100% pewien, że ustawienie tokena na security.context jest konieczne, jeśli masz zamiar przekierować od razu. Ale to nie wydaje się boleć, więc odeszłam. to.

Następnie ważna część, ustawienie zmiennej sesji. Konwencja nazewnictwa zmiennych to _security_ po której następuje nazwa zapory sieciowej, w tym przypadku main tworząc _security_main

 131
Author: Chausser,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-03-30 18:00:53

W końcu to rozgryzłem.

Po rejestracji użytkownika, powinieneś mieć dostęp do instancji obiektu niezależnie od tego, co ustawiłeś jako jednostkę użytkownika w konfiguracji dostawcy. Rozwiązaniem jest utworzenie nowego tokena z tym podmiotem użytkownika i przekazanie go do kontekstu bezpieczeństwa. Oto przykład oparty na mojej konfiguracji:

RegistrationController.php:

$token = new UsernamePasswordToken($userEntity, null, 'main', array('ROLE_USER'));
$this->get('security.context')->setToken($token);

Gdzie main to nazwa zapory sieciowej dla Twojej aplikacji(dzięki, @ Joe). To naprawdę wszystko. system teraz uważa, że twój użytkownik jest w pełni zalogowany jako użytkownik, który właśnie utworzył.

EDIT: za komentarz @Miquel, zaktualizowałem przykładowy kod kontrolera, aby zawierał rozsądną domyślną rolę dla nowego użytkownika(choć oczywiście można to dostosować do konkretnych potrzeb aplikacji).

 64
Author: Problematic,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-10-19 15:12:32

Jeśli masz obiekt UserInterface (i tak powinno być przez większość czasu), możesz użyć funkcji getRoles, którą implementuje do ostatniego argumentu. Jeśli więc utworzysz funkcję logUser, powinna ona wyglądać tak:

public function logUser(UserInterface $user) {
    $token = new UsernamePasswordToken($user, null, 'main', $user->getRoles());
    $this->container->get('security.context')->setToken($token);
}
 6
Author: Cédric Nirousset,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-04-23 21:53:48

Używam Symfony 2.2 i moje doświadczenie było nieco inne niż , więc jest to połączona Wersja wszystkich informacji z tego pytania plus niektóre z moich własnych.

Myślę, że Joe jest w błędzie co do wartości $providerKey, trzeciego parametru konstruktora UsernamePasswordToken. Ma to być klucz dostawcy uwierzytelniania (Nie użytkownika). Jest używany przez system uwierzytelniania do rozróżniania tokenów utworzonych dla różnych dostawców. Każdy dostawca który pochodzi z UserAuthenticationProvider uwierzytelni tylko tokeny, których klucz dostawcy pasuje do własnego. Na przykładUsernamePasswordFormAuthenticationListener ustawia klucz tworzonego tokenu tak, aby pasował do odpowiadającego mu klucza DaoAuthenticationProvider. Dzięki temu pojedynczy firewall może mieć wiele dostawców nazwy użytkownika i hasła bez ich wchodzenia na siebie. Dlatego musimy wybrać klucz, który nie będzie sprzeczny z żadnymi innymi dostawcami. Używam 'new_user'.

Mam kilka systemów w innych częściach mojej aplikacji zależy to od zdarzenia sukcesu uwierzytelniania i nie jest wywoływane przez samo ustawienie tokena w kontekście. Musiałem wyciągnąć EventDispatcher z kontenera i odpalić Zdarzenie ręcznie. Zdecydowałem się nie uruchamiać również interaktywnego zdarzenia logowania , ponieważ uwierzytelniamy użytkownika w sposób niejawny, a nie w odpowiedzi na wyraźne żądanie logowania.

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 ) );

Zauważ, że użycie $this->get( .. ) zakłada, że urywek jest w metodzie kontrolera. Jeśli używasz kodu gdzie indziej będziesz trzeba je zmienić, aby wywołać ContainerInterface::get( ... ) w sposób odpowiedni dla środowiska. Tak się składa, że moje jednostki użytkownika implementują UserInterface, więc mogę ich używać bezpośrednio z tokenem. Jeśli twój nie ma, musisz znaleźć sposób, aby je przekonwertować na UserInterface instancje.

Ten kod działa, ale wydaje mi się, że hakuje architekturę uwierzytelniania Symfony zamiast z nią pracować. Prawdopodobnie bardziej poprawne byłoby zaimplementowanie nowego dostawcy uwierzytelniania z własną klasą tokenu, a nie niż porwanie UsernamePasswordToken. Ponadto korzystanie z odpowiedniego dostawcy oznaczałoby, że Wydarzenia zostały obsłużone za Ciebie.

 6
Author: Sam Hanes,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 10:31:28

Na wypadek, gdyby ktoś miał to samo pytanie, które skłoniło mnie do powrotu tutaj:

Wywołanie

$this->container->get('security.context')->setToken($token); 

Wpływa tylko na prąd security.context dla użytej trasy.

Tzn. użytkownik może zalogować się tylko z adresu URL znajdującego się pod kontrolą Firewalla.

(w razie potrzeby Dodaj wyjątek dla trasy - IS_AUTHENTICATED_ANONYMOUSLY)

 4
Author: daemonl,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-07-10 10:09:48

Jak już wspomniano, ten nieuchwytny parametr $providerKey jest w rzeczywistości niczym innym jak nazwą reguły zapory, 'foobar' w przypadku poniższego przykładu.

firewalls:
    foobar:
        pattern:    /foo/
 2
Author: Nim,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-04-17 06:15:19

Próbowałem wszystkich odpowiedzi tutaj i żadna nie zadziałała. Jedynym sposobem na uwierzytelnienie moich użytkowników na kontrolerze jest wykonanie zapytania podrzędnego, a następnie przekierowanie. Oto Mój kod, używam silexu, ale można go łatwo dostosować do 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'));
 2
Author: Diego Castro,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-09-03 10:36:18

Na Symfony w wersji 2.8.11 (prawdopodobnie działa dla starszych i nowszych wersji), Jeśli używasz FOSUserBundle po prostu zrób to:

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.).
}

Nie ma potrzeby wysyłania zdarzenia, jak widziałem w innych rozwiązaniach.

Inpired from Fos\UserBundle\Controller\RegistrationController:: authenticateUser

(od kompozytora.wersja JSON FOSUserBundle: "friendsofsymfony/user-bundle": "~1.3")

 0
Author: Nico,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-06-06 13:40:14