I’m reviewing some hacks that went into our codebase when we adopted zend-expressive-session
. They both involve the need to access the session ID from a handler, before the SessionMiddleware
has persisted the session and added the cookie to the response.
We have two use cases:
- We need the session ID to generate a CSRF token. Our sessions are lockless, so the token is stored separately from the session. When a user first hits the login page, no session exists.
- On login we check whether any other session is using the same credentials and regenerate the session. To do this we need to store the regenerated ID against the user record. But it isn’t available until
SessionMiddleware
handles the reponse.
The hack we have in place involves:
- Injecting the
SessionPersistenceInterface
into our login handler. - Performing a merry dance with the cookies returned in the response from
persistSession()
, passing them through toinitializeSessionFromRequest()
and finally get the new session from that request. - Calling
persistSession()
again when we return the response so the new cookie is set. - Wrapping
PhpSessionPersistence
so it checks for the existence of a session cookie before overwriting it with the now-useless proxied session ID, and injecting the wrapped instance into theSessionMiddeware
.
There must be a better way. Why can’t I just $session->start()
?
So I’d like two new interfaces:
interface StartableSessionInterface
{
/**
* Starts the session and returns session instance
*
* @return SessionInterface
*/
public function start() : SessionInterface;
}
and
interface StartablePersistenceInterface
{
/**
* Starts the given session and returns started session instance
*
* @param SessionInterface $session
* @return SessionInterface
*/
public function start(SessionInterface $session) : SessionInterface;
}
PhpSessionPersistence
would implement StartablePersistenceInterface
. And LazySession
would implement StartableSessionInterface
, replacing its proxied session with the response from the persistence, if supported, or barfing if not.
I’ll do a PR for this. But I’d love to know if there’s a better approach.
What do you think?