Search code examples
phpsession-cookieszend-sessionzend-framework3

Set session cookie only when user is logged in


I'm building a ZF3 based application, and I'm trying to get the session cookie to be set only when a user has successfully logged in. And remove it on logout.

There seems to not be such a feature in the ZF3 Session, or at least I have not been able to find it in the zend-session configuration documentation.

Right now, the framework creates the PHPSESSID session cookie (the default name) when any page is opened and no session cookie is found.

Until the user actually logs in, that cookie is completely useless for my application, since I don't have the need to remember session data for guests.

I'm looking to alter this behavior, so that the session cookie generation model is this:

  • Don't create a session cookie until a valid login happens. Simply treat the session as a new one, but skip creating the cookie.
  • Create the session cookie when the user logs in, with the life time specified in the configuration.
  • Destroy the session cookie when the user logs out.

Any pointers are appreciated.


Solution

  • Just in case someone is asking a similar question.

    After a bit of fiddling, I have found a solution, but also some unearthed some undesired side-effects.

    Solution

    As Raphioly-San pointed out in the question comment, you need to access the session to determine if a user is logged in. This means that you need to start the session every time. This, in turn, generates the session cookie.

    So, the only solution is to destroy the session cookie when the application finishes, if the user is not logged in, and not preventing the session cookie from being generated at all.

    Implementation

    When bootstraping the module, add a listener for MvcEvent::EVENT_FINISH, and in there destroy the current session when the application exits, if no user is logged in.

    namespace Application;
    
    class Module
    {
        public function onBootstrap(MvcEvent $event) {
            $event->getApplication()
                ->getEventManager()
                ->attach(
                    MvcEvent::EVENT_FINISH,
                    function() use ($event){
                        // Stop if a user is logged in
                        $userLoggedIn = $event->getApplication()->getServiceManager()->get(AuthenticationService::class)->hasIdentity();
    
                        if ($userLoggedIn) {
                            return;
                        }
    
                        // Destroy session cookie
                        // Note: this is not the most elegant solution, but it will suffice for this example
                        $params = session_get_cookie_params();
                        setcookie(session_name(), '', 1, $params['path'], $params['domain'], $params['secure'], $params['httponly']);
                        session_destroy();
                        session_write_close();
                    },
                    -999
                );
        }
    }
    

    Side-effects

    Destroying the session cookie breaks at least the flash messenger component, when it is used for guests.

    Other components may fail to work properly as well.

    Conclusions

    I researched this solution, as requested by a server administrator, since cookies cause issues when using the Varnish caching system.

    While the basic implementation works, I am still researching the side effects.