简体   繁体   中英

Anonymous user object in symfony

I'm using the basic user login/logout system provided with Symfony and it works fine as long as people log in. In that case the $user object is always provided as needed.

The problem is then when logged out (or not lgged in yet) there is no user object. Is there a possibility to have (in that case) a default user object provided with my own default values?

Thanks for your suggestions

Because the solution mention above by @Chopchop (thanks anyway for your effort) didn't work here I wrote a little workaround.

I created a new class called myController which extends Controller. The only function i override is the getUser() function. There I implement it like this:

public function getUser()
{
    $user = Controller::getUser();

    if ( !is_object($user) )            
    {
        $user = new \ACME\myBundle\Entity\User();

        $user->setUserLASTNAME ('RaRa');
        $user->setID (0);
        // etc...
    }

    return $user;
}

This works fine for me now. The only problem is that you really have to be careful NOT to forget to replace Controller by myController in all your *Controller.php files. So, better suggestions still welcome.

Works in Symfony 3.3

Using the suggestion of @Sfblaauw, I came up with a solution that uses a CompilerPass .

AppBundle/AppBundle.php

class AppBundle extends Bundle
{
    public function build(ContainerBuilder $container)
    {
        parent::build($container);
        $container->addCompilerPass(new OverrideAnonymousUserCompilerPass());
    }
}

OverrideAnonymousUserCompilerPass.php

class OverrideAnonymousCompilerPass implements CompilerPassInterface
{
    public function process(ContainerBuilder $container)
    {
        $definition = $container->getDefinition('security.authentication.listener.anonymous');
        $definition->setClass(AnonymousAuthenticationListener::class);
    }
}

AnonymousAuthenticationListener.php

class AnonymousAuthenticationListener implements ListenerInterface
{
    private $tokenStorage;
    private $secret;
    private $authenticationManager;
    private $logger;

    public function __construct(TokenStorageInterface $tokenStorage, $secret, LoggerInterface $logger = null, AuthenticationManagerInterface $authenticationManager = null)
    {
        $this->tokenStorage = $tokenStorage;
        $this->secret = $secret;
        $this->authenticationManager = $authenticationManager;
        $this->logger = $logger;
    }

    public function handle(GetResponseEvent $event)
    {
        if (null !== $this->tokenStorage->getToken()) {
            return;
        }

        try {
            // This is the important line:
            $token = new AnonymousToken($this->secret, new AnonymousUser(), array());
            if (null !== $this->authenticationManager) {
                $token = $this->authenticationManager->authenticate($token);
            }

            $this->tokenStorage->setToken($token);

            if (null !== $this->logger) {
                $this->logger->info('Populated the TokenStorage with an anonymous Token.');
            }
        } catch (AuthenticationException $failed) {
            if (null !== $this->logger) {
                $this->logger->info('Anonymous authentication failed.', array('exception' => $failed));
            }
        }
    }
}

This file is a copy of the AnonymousAuthenticationListener that comes with Symfony, but with the AnonymousToken constructor changed to pass in an AnonymousUser class instead of a string. In my case, AnonymousUser is a class that extends my User object, but you can implement it however you like.

These changes mean that {{ app.user }} in Twig and UserInterface injections in PHP will always return a User : you can use isinstance to tell if it's an AnonymousUser , or add a method isLoggedIn to your User class which returns true in User but false in AnonymousUser .

you can redirect the user not authenticated and force a fake login (to create a user ANONYMOUS)

and set it as well on logout

public function logoutAction(){

    $em = $this->getDoctrine()->getManager();
    $user = $em->getRepository('VendorBundle:User')->findByUserName('annonymous');

    $session = $this->getRequest()->getSession();
    $session->set('user', $user);
}

and if user is not set

public function checkLoginAction(){
    if(!$session->get('user')){
         $em = $this->getDoctrine()->getManager();
         $user = $em->getRepository('VendorBundle:User')->findByUserName('annonymous');
         $session = $this->getRequest()->getSession();
         $session->set('user', $user);
    }
    //this->redirect('/');
}

in you security.yml

security:
    firewalls:           
        main:
            access_denied_url: /check_login/

access_control:
        - { path: ^/$, role: ROLE_USER }

This is only an example i haven't tested (and will probably don't, since i don't get the purpose of doing this:) )

Using Symfony 2.6

Like Gordon says use the authentication listener to override the default anonymous user. Now you can add the properties that you need to the anonymous user, in my case the language and the currency.

security.yml

parameters:
    security.authentication.listener.anonymous.class: AppBundle\Security\Http\Firewall\AnonymousAuthenticationListener

AnonymousAuthenticationListener.php

namespace AppBundle\Security\Http\Firewall;

...
use AppBundle\Security\User\AnonymousUser;

class AnonymousAuthenticationListener implements ListenerInterface
{
    ...

    public function handle(GetResponseEvent $event)
    {
        ...

        try {
            $token = new AnonymousToken($this->key, new AnonymousUser(), array());
            ...
        }
    }
}

AnonymousUser.php

class AnonymousUser implements UserInterface
{
    public function getUsername() { return 'anon.'; }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM