IT박스

자동 등록 후 사용자 인증

itboxs 2020. 8. 5. 08:02
반응형

자동 등록 후 사용자 인증


우리는 Symfony 2에서 처음부터 비즈니스 응용 프로그램을 구축하고 있으며 사용자 등록 흐름에 약간의 혼란이 있습니다. 사용자가 계정을 만든 후에는 대신 자격 증명을 사용하여 자동으로 로그인해야합니다 자격 증명을 즉시 다시 제공해야합니다.

누구든지 이것에 대해 경험이 있거나 올바른 방향으로 나를 가리킬 수 있습니까?


심포니 4.0

이 프로세스는 symfony 3에서 4로 변경되지 않았지만 다음은 새로 권장되는 AbstractController를 사용하는 예입니다. security.token_storagesession서비스 모두 상위 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.
    }

}

심포니 2.6.x-심포니 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 용으로 업데이트 할 준비가되었습니다.

https://github.com/symfony/symfony/blob/2.6/UPGRADE-2.6.md 에서 보안의 2.6 변경 사항에 대한 자세한 내용을 확인할 수 있습니다.

심포니 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
    }

}

For the token creation you will want to create a UsernamePasswordToken, This accepts 4 parameters: User Entity, User Credentials, Firewall Name, User Roles. You dont need to provide the user credentials for the token to be valid.

Im not 100% sure that setting the token on the security.context is necessary if you are just going to redirect right away. But it doesnt seem to hurt so i have left it.

Then the important part, setting the session variable. The variables naming convention is _security_ followed by your firewall name, in this case main making _security_main


Figured this one out, finally.

After user registration, you should have access to an object instanceof whatever you've set as your user entity in your provider configuration. The solution is to create a new token with that user entity and pass it into the security context. Here's an example based on my setup:

RegistrationController.php:

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

Where main is the name of the firewall for your application (thanks, @Joe). That's really all there is to it; the system now considers your user fully logged in as the user they've just created.

EDIT: Per @Miquel's comment, I've updated the controller code sample to include a sensible default role for a new user (though obviously this can be adjusted according to your application's specific needs).


If you have a UserInterface object (and that should be the case most of the time) you might want to use the getRoles function that it implements for the last argument. So if you create a function logUser, it should looks like that:

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

I'm using Symfony 2.2 and my experience was slightly different than Problematic's, so this is a combined version of all the info from this question plus some of my own.

I think Joe is wrong about the value of $providerKey, the third parameter to the UsernamePasswordToken constructor. It's supposed to be the key of an authentication (not user) provider. It's used by the authentication system to distinguish between tokens created for different providers. Any provider which descends from UserAuthenticationProvider will only authenticate tokens whose provider key matches its own. For example, the UsernamePasswordFormAuthenticationListener sets the key of the token it creates to match that of its corresponding DaoAuthenticationProvider. That lets a single firewall have multiple username+password providers without them stepping on each other. We therefore need to choose a key that won't conflict with any other providers. I use 'new_user'.

I have a few systems in other parts of my application that depend on the authentication success event, and that isn't fired by just setting the token on the context. I had to get the EventDispatcher from the container and fire the event manually. I decided against also firing an interactive login event because we're authenticating the user implicitly, not in response to an explicit login request.

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

Note that use of $this->get( .. ) assumes the snippet is in a controller method. If you're using the code somewhere else you'll have to change those to call ContainerInterface::get( ... ) in a way appropriate to the environment. As it happens my user entities implement UserInterface so I can use them directly with the token. If yours don't you'll have to find a way to convert them to UserInterface instances.

That code works, but I feel like it's hacking around Symfony's authentication architecture rather than working with it. It would probably be more correct to implement a new authentication provider with its own token class rather than hijacking the UsernamePasswordToken. Also, using a proper provider would mean that the events were handled for you.


In case anyone has the same follow-on question which kept me coming back to here:

Calling

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

only effects the current security.context for the route used.

I.e. you can only log in a user from a url within the firewall's control.

(Add an exception for the route if needed - IS_AUTHENTICATED_ANONYMOUSLY)


As Problematic here already mentioned, this elusive $providerKey parameter is in reality nothing more than the name of your firewall rule, 'foobar' in the case of the example below.

firewalls:
    foobar:
        pattern:    /foo/

I tried all the answers here and none worked. The only way I could authenticate my users on a controller is by making a subrequest and then redirecting. Here is my code, I'm using silex but you can easily adapt it to 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'));

On Symfony version 2.8.11 (probably working for older and newer versions), if you use FOSUserBundle simply do this :

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

No need to dispatch event as I've seen in other solutions.

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

(from composer.json FOSUserBundle version : "friendsofsymfony/user-bundle": "~1.3")

참고URL : https://stackoverflow.com/questions/5886713/automatic-post-registration-user-authentication

반응형