Автоматическая проверка подлинности пользователя после регистрации



мы создаем бизнес-приложение с нуля в Symfony 2, и я столкнулся с небольшой проблемой с потоком регистрации пользователей: после того, как пользователь создает учетную запись, они должны автоматически войти в систему с этими учетными данными, а не быть немедленно вынуждены снова предоставить свои учетные данные.



У кого-нибудь был опыт с этим, или в состоянии указать мне в правильном направлении?

514   8  

8 ответов:

Symfony 4.0

этот процесс не изменился с symfony 3 на 4, но вот пример использования недавно рекомендованного AbstractController. Оба security.token_storage и session услуги регистрируются в Родительском getSubscribedServices метод, поэтому вам не нужно добавлять их в свой контроллер.

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

начиная с symfony 2.6 security.context является устаревшим в пользу security.token_storage. Контроллер теперь может просто быть:

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

}

в то время как это устарело вы все еще можете использовать security.context как это было сделано для обратной совместимости. Просто будьте готовы обновить его для Symfony 3

вы можете прочитать больше об изменениях 2.6 для безопасности здесь:https://github.com/symfony/symfony/blob/2.6/UPGRADE-2.6.md

Symfony 2.3.x

для этого в symfony 2.3 вы больше не можете просто установить токен в безопасности контекст. Также необходимо сохранить маркер в сеансе.

предполагая, что файл безопасности с брандмауэром, как:

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

и действие контроллера тоже похоже:

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
    }

}

для создания токена вы хотите создать UsernamePasswordToken, это принимает 4 параметра: сущность пользователя, учетные данные пользователя, имя брандмауэра, роли пользователей. Вам не нужно предоставлять учетные данные пользователя для маркер, чтобы быть действительным.

Я не на 100% уверен, что установка маркера включена элемент security.context необходимо, если вы просто собираетесь перенаправить сразу. Но это, кажется, не больно, так что я оставил его.

затем важная часть, устанавливающая переменную сеанса. Соглашение об именовании переменных -_security_ затем следует имя брандмауэра, в этом случае main делая _security_main

наконец-то понял это.

после регистрации пользователя, вы должны иметь доступ к объекту instanceof все, что вы установили в качестве объекта пользователя в конфигурации поставщика. Решение состоит в том, чтобы создать новый маркер с этой сущностью пользователя и передать его в контекст безопасности. Вот пример, основанный на моей настройке:

RegistrationController.php:

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

здесь main это имя брандмауэра для вашего приложения (спасибо, @Joe). Это действительно все, что есть теперь система считает, что ваш пользователь полностью вошел в систему как пользователь, которого они только что создали.

EDIT: в комментарии @Miquel я обновил образец кода контроллера, чтобы включить разумную роль по умолчанию для нового пользователя (хотя, очевидно, это можно настроить в соответствии с конкретными потребностями вашего приложения).

Если у вас есть объект UserInterface (и это должно быть так большую часть времени), вы можете использовать функцию getRoles, которую она реализует для последнего аргумента. Поэтому, если вы создаете функцию logUser, она должна выглядеть так:

public function logUser(UserInterface $user) {
    $token = new UsernamePasswordToken($user, null, 'main', $user->getRoles());
    $this->container->get('security.context')->setToken($token);
}

я использую Symfony 2.2 и мой опыт немного отличается от проблематично это, так что это комбинированная версия всей информации из этого вопроса плюс некоторые из моих собственных.

Я думаю Джо неверно о значении $providerKey третий параметр UsernamePasswordToken конструктор. Он должен быть ключом поставщика аутентификации (не пользователя). Он используется системой аутентификации для различения токенов, созданных для разных услуги поставщиков. Любой провайдер, который происходит от UserAuthenticationProvider будет только аутентифицировать токены, ключ поставщика которых соответствует его собственному. Например,UsernamePasswordFormAuthenticationListener устанавливает ключ токена, который он создает, чтобы соответствовать ключу соответствующего DaoAuthenticationProvider. Это позволяет одному брандмауэру иметь несколько поставщиков имени пользователя и пароля, не наступая друг на друга. Поэтому нам нужно выбрать ключ, который не будет конфликтовать с другими поставщиками. Я использую 'new_user'.

у меня есть несколько систем в других частях моего приложения, которые зависят от событие успеха аутентификации, и это не срабатывает, просто установив маркер в контексте. Я должен был получить EventDispatcher из контейнера и запустить событие вручную. Я решил также не стрелять интерактивный вход в систему событие потому что мы имплицитно аутентификации пользователя, а не в ответ на явный запрос на вход.

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

обратите внимание, что использование $this->get( .. ) предполагает, что фрагмент находится в методе контроллера. Если вы используете код где-то еще, вам придется изменить их, чтобы вызвать ContainerInterface::get( ... ) в соответствии с окружающей средой. Как это происходит, мои пользовательские сущности реализуют UserInterface так что я могу использовать их непосредственно с маркером. Если у вас нет, вам придется найти способ конвертировать их в UserInterface экземпляров.

этот код работает, но я чувствую, что он взламывает архитектуру аутентификации Symfony, а не работает с ней оно. Наверное, было бы правильнее внедрить новый поставщик аутентификации со своим собственным классом токенов, а не угон UsernamePasswordToken. Кроме того, использование надлежащего поставщика будет означать, что события были обработаны для вас.

в случае, если у кого-то есть тот же следующий вопрос, который заставил меня вернуться сюда:

вызов

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

влияет только на ток security.context для используемого маршрута.

т. е. вы можете войти в систему только с url-адреса в пределах управления брандмауэра.

(при необходимости добавьте исключение для маршрута -IS_AUTHENTICATED_ANONYMOUSLY)

Как уже упоминалось, этот неуловимый параметр $providerKey на самом деле является не более чем именем вашего правила брандмауэра, "foobar" в случае приведенного ниже примера.

firewalls:
    foobar:
        pattern:    /foo/

я попробовал все ответы здесь, и ни один не работал. Единственный способ проверки подлинности пользователей на контроллере это сделать подзапрос и потом редиректом. Вот мой код, я использую silex, но вы можете легко адаптировать его к 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'));

на Symfony версии 2.8.11 (вероятно, работает для более старых и новых версий),Если вы используете FOSUserBundle просто сделать это :

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

нет необходимости отправлять событие, как я видел в других решениях.

inpired from FOS\UserBundle\Controller\RegistrationController:: authenticateUser

(от композитора.версия json FOSUserBundle: "friendsofsymfony / user-bundle": "~1.3")

Comments

    Ничего не найдено.