Jak programowo logować / uwierzytelniać użytkownika?
Chciałbym zalogować się bezpośrednio po procesie rejestracji, bez przechodzenia przez formularz logowania.
Czy to możliwe ? Znalazłem rozwiązanieFOSUserBundle
, ale nie używam go w projekcie, nad którym pracuję.
Oto moja Ochrona.yml, pracuję z dwoma firewallami.
Koder zwykłego tekstu służy tylko do testowania.
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 }
3 answers
Tak, możesz to zrobić za pomocą czegoś podobnego do następującego:
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
}
}
Wywołanie zdarzenia na końcu nie jest wykonywane automatycznie, gdy ustawisz token w kontekście, podczas gdy normalnie byłoby to przy użyciu np. formularza logowania lub podobnego. Stąd powód włączenia go tutaj. Może być konieczne dostosowanie typu używanego tokenu, w zależności od przypadku użycia - UsernamePasswordToken
pokazany powyżej jest tokenem podstawowym, ale w razie potrzeby możesz użyć innych.
Edit : dostosowałem powyższy kod do wyjaśnij parametr "public", a także dodaj role użytkownika do tworzenia tokena, na podstawie poniższego komentarza.
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-11-01 09:47:56
Zaakceptowana wersja nie będzie działać z symfony 3.3. Użytkownik zostanie uwierzytelniony w następnym żądaniu zamiast bieżącego. Powodem jest to, że ContextListener sprawdza istnienie poprzedniej sesji, a jeśli nie istnieje, wyczyści security TokenStorage. Jedynym sposobem na obejście tego (hackish as hell) jest sfałszowanie istnienia poprzedniej sesji poprzez ręczne inicjowanie sesji (i pliku cookie) na bieżące żądanie.
Daj znać, jeśli znajdziesz lepsze rozwiązanie.BTW Nie jestem pewien, czy należy to połączyć z przyjętym rozwiązaniem.
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);
}
Powyższy kod zakłada, że nazwa zapory sieciowej (lub nazwa współdzielonego kontekstu) to common
.
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-07-17 15:18:12
Spróbuj tego : dla użytkowników Symfony 3 , nie zapomnij dokonać tej korekty, aby sprawdzić równość haseł (ponieważ metoda pokazana do testowania hasła pod tym linkiem nie działa):
$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
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-10-22 17:45:45