How to check if a user is logged in Symfony2 inside a controller?
Asked Answered
R

7

79

I read here how to check the login status of a user by inside a twig template for a Symfony2-based website. However, I need to know how to check if the user is logged in from inside a controller. I was quite sure the the following code was right:

$user = $this->get('security.context')->getToken()->getUser();

but it always return something, e.g. a logged user or an anonymous user.

Any idea?

Repulsion answered 22/4, 2012 at 19:55 Comment(2)
can't you could check if $user != "anon."?Spinneret
Well, I was looking for something more "secure". Isn't another way, i.e. some function to call?Repulsion
T
153

Warning: Checking for 'IS_AUTHENTICATED_FULLY' alone will return false if the user has logged in using "Remember me" functionality.

According to Symfony 2 documentation, there are 3 possibilities:

IS_AUTHENTICATED_ANONYMOUSLY - automatically assigned to a user who is in a firewall protected part of the site but who has not actually logged in. This is only possible if anonymous access has been allowed.

IS_AUTHENTICATED_REMEMBERED - automatically assigned to a user who was authenticated via a remember me cookie.

IS_AUTHENTICATED_FULLY - automatically assigned to a user that has provided their login details during the current session.

Those roles represent three levels of authentication:

If you have the IS_AUTHENTICATED_REMEMBERED role, then you also have the IS_AUTHENTICATED_ANONYMOUSLY role. If you have the IS_AUTHENTICATED_FULLY role, then you also have the other two roles. In other words, these roles represent three levels of increasing "strength" of authentication.

I ran into an issue where users of our system that had used "Remember Me" functionality were being treated as if they had not logged in at all on pages that only checked for 'IS_AUTHENTICATED_FULLY'.

The answer then is to require them to re-login if they are not authenticated fully, or to check for the remembered role:

$securityContext = $this->container->get('security.authorization_checker');
if ($securityContext->isGranted('IS_AUTHENTICATED_REMEMBERED')) {
    // authenticated REMEMBERED, FULLY will imply REMEMBERED (NON anonymous)
}

Hopefully, this will save someone out there from making the same mistake I made. I used this very post as a reference when looking up how to check if someone was logged in or not on Symfony 2.

Source: http://symfony.com/doc/2.3/cookbook/security/remember_me.html#forcing-the-user-to-re-authenticate-before-accessing-certain-resources

Transalpine answered 20/10, 2012 at 1:16 Comment(9)
Actually, you could just use $securityContext->isGranted('IS_AUTHENTICATED_REMEMBERED'), since the roles are hierarchical. So having IS_AUTHENTICATED_FULLY implies that the user also has IS_AUTHENTICATED_REMEMBERED.Olivares
Not true. IS_AUTHENTICATED_REMEMBERED returns true only when the user uses "Remember me" functionality. Having IS_AUTHENTICATED_FULLY does imply IS_AUTHENTICATED_REMEMBERED, but not the other way around.Transalpine
Right. If IS_AUTHENTICATED_FULLY also guarantees that a user has IS_AUTHENTICATED_REMEMBERED, then you only ever need to check for IS_AUTHENTICATED_REMEMBERED.Olivares
Think of them like subclasses. If B is a subclass of A, then anything that is a subclass of B will also be a subclass of A. Thus, checking that a class is a subclass of both A and B is redundant.Olivares
I read you answer and I decided to put it as selected answer.Repulsion
How is this handled when you have different ROLES. For example, I have a ROLE_USER and a ROLE_ADMIN, that is required for certain areas of the site, I would like to allow both of these types of users access to their respective areas with the IS_AUTHENTICATED_REMEMBERED level. How can I accomplish this?Margarettemargarida
BTW, use $this->container->get('security.authorization_checker') instead (new in 2.6)Farant
"Checking for 'IS_AUTHENTICATED_FULLY' alone will return false if the user has logged in using "Remember me" functionality" This is not the case in Symfony 3 (I'm using 3.3.5). In other words, - { path: ^/some-path, role: IS_AUTHENTICATED_FULLY } is accessible for users whether they check 'Remember me' or not.Heinous
I don't like redundancy, duplicate code is bad m'kay. BUT sometimes it is not a bad thing to be explicit. Personally I would check for both simply because the code would be easier to understand for my future self and others. Even though it is true, the inheritance in this case is not logical, and therefore might be confusing in the future.Debt
A
56

SecurityContext will be deprecated in Symfony 3.0

Prior to Symfony 2.6 you would use SecurityContext.
SecurityContext will be deprecated in Symfony 3.0 in favour of the AuthorizationChecker.

For Symfony 2.6+ & Symfony 3.0 use AuthorizationChecker.


Symfony 2.6 (and below)

// Get our Security Context Object - [deprecated in 3.0]
$security_context = $this->get('security.context');
# e.g: $security_context->isGranted('ROLE_ADMIN');

// Get our Token (representing the currently logged in user)
$security_token = $security_context->getToken();
# e.g: $security_token->getUser();
# e.g: $security_token->isAuthenticated();
# [Careful]             ^ "Anonymous users are technically authenticated"

// Get our user from that security_token
$user = $security_token->getUser();
# e.g: $user->getEmail(); $user->isSuperAdmin(); $user->hasRole();

// Check for Roles on the $security_context
$isRoleAdmin = $security_context->isGranted('ROLE_ADMIN');
# e.g: (bool) true/false

Symfony 3.0+ (and from Symfony 2.6+)

security.context becomes security.authorization_checker.
We now get our token from security.token_storage instead of the security.context

// [New 3.0] Get our "authorization_checker" Object
$auth_checker = $this->get('security.authorization_checker');
# e.g: $auth_checker->isGranted('ROLE_ADMIN');

// Get our Token (representing the currently logged in user)
// [New 3.0] Get the `token_storage` object (instead of calling upon `security.context`)
$token = $this->get('security.token_storage')->getToken();
# e.g: $token->getUser();
# e.g: $token->isAuthenticated();
# [Careful]            ^ "Anonymous users are technically authenticated"

// Get our user from that token
$user = $token->getUser();
# e.g (w/ FOSUserBundle): $user->getEmail(); $user->isSuperAdmin(); $user->hasRole();

// [New 3.0] Check for Roles on the $auth_checker
$isRoleAdmin = $auth_checker->isGranted('ROLE_ADMIN');
// e.g: (bool) true/false

Read more here in the docs: AuthorizationChecker
How to do this in twig?: Symfony 2: How do I check if a user is not logged in inside a template?

Axle answered 6/8, 2015 at 21:34 Comment(1)
From inside symfony Controller you can just write $this->isGranted($role, $obj, $errMsg). The denyAccessUnlessGranted() function and the isGranted() functions are both just shortcuts to call isGranted() on the security.authorization_checker service.Christophe
S
46

Try this:

if( $this->container->get('security.context')->isGranted('IS_AUTHENTICATED_FULLY') ){
    // authenticated (NON anonymous)
}

Further information:

"Anonymous users are technically authenticated, meaning that the isAuthenticated() method of an anonymous user object will return true. To check if your user is actually authenticated, check for the IS_AUTHENTICATED_FULLY role."

Source: http://symfony.com/doc/current/book/security.html

Spinneret answered 22/4, 2012 at 20:5 Comment(6)
Yes! It works... thank you so much! However, do you think that the $user != "anon." is secure enough? My fear is that a new release could change the value returned by an anonymous user! Isn't it possible?Repulsion
Well.. since there is this solution provided by Symfony, I'd suggest you to use this one (isGranted). I don't think they're going to change the behaviour of such a basic feature as the security component. By the way, using isGranted is far more professional and clean than a simple string comparison.Spinneret
Thanks again for the complete answer!Repulsion
BTW, use $this->container->get('security.authorization_checker') instead (new in 2.6)Farant
You have requested a non-existent service "security.context".Flyte
security.context is deprecatedParsnip
C
9

To add to answer given by Anil, In symfony3, you can use $this->getUser() to determine if the user is logged in, a simple condition like if(!$this->getUser()) {} will do.

If you look at the source code which is available in base controller, it does the exact same thing defined by Anil.

Crystlecs answered 11/2, 2017 at 8:47 Comment(1)
The $this->getUser() approach is working just fine, just tested it in Symfony 5. Also, Suppose in controller you have $someVar = $this->getUser(); and pass it to twig. Then you can do somewhere inside body tag {{dump(someVar)}} or {% dump(someVar) %} and you will get either a null or the content of user object.Flocculate
A
8

If you are using security annotation from the SensioFrameworkExtraBundle, you can use a few expressions (that are defined in \Symfony\Component\Security\Core\Authorization\ExpressionLanguageProvider):

  • @Security("is_authenticated()"): to check that the user is authed and not anonymous
  • @Security("is_anonymous()"): to check if the current user is the anonymous user
  • @Security("is_fully_authenticated()"): equivalent to is_granted('IS_AUTHENTICATED_FULLY')
  • @Security("is_remember_me()"): equivalent to is_granted('IS_AUTHENTICATED_REMEMBERED')
Adrianneadriano answered 27/9, 2016 at 8:35 Comment(0)
K
6

If you using roles you could check for ROLE_USER that is the solution i use:

if (TRUE === $this->get('security.authorization_checker')->isGranted('ROLE_USER')) {
    // user is logged in
} 
Karinkarina answered 1/3, 2015 at 22:8 Comment(1)
Assuming your app assigns ROLE_USER to everyone. Not all apps do.Rentschler
E
1

It's good practise to extend from a baseController and implement some base functions implement a function to check if the user instance is null like this if the user form the Userinterface then there is no user logged in

/**

*/
class BaseController extends AbstractController
{

    /**
     * @return User

     */
    protected function getUser(): ?User
    {
        return parent::getUser();
    }

    /**
     * @return bool
     */
    protected function isUserLoggedIn(): bool
    {
        return $this->getUser() instanceof User;
    }
}
Equator answered 15/1, 2021 at 19:31 Comment(2)
I'm not sure why this was downvoted. I am a beginner at Symfony but accessing $this->user() from a controller works perfectly.Lohman
Because I think it's actually not a good practice to do that like this. I prefer composition way more. What if another service wants to know if user is logged in. Also i don't know why ovewrite getUser() method. Wrong and useless annotations on top of it.Ardath

© 2022 - 2024 — McMap. All rights reserved.