Warm tip: This article is reproduced from serverfault.com, please click

laravel and multi-sessions from the same browser

发布于 2015-10-23 21:38:35

In our web app, If I use a single browser, login to our application as user A, open another tab and login as user B - User A loses his session data. I assume this is due to a shared cookie made out with the user-agent. Is there a way to concat its name with a username? so that sessions can co-exist between concurrent logged in users using the same browser on the same machine?

We use Laravel 5. Is there any way around it?

Questioner
JasonGenX
Viewed
0
Chris 2015-10-29 10:19:04

Laravel Session Background

Sessions

Skip this section for a quick easy solution

In Laravel, session cookies are created via the Illuminate\Session\SessionManager class, namely through the buildSession method:

SessionManager::buildSession

protected function buildSession($handler)
{
    if ($this->app['config']['session.encrypt']) {
        return new EncryptedStore(
            $this->app['config']['session.cookie'], $handler, $this->app['encrypter']
        );
    } else {
        return new Store($this->app['config']['session.cookie'], $handler);
    }
}

In this method we can clearly see that the name of the session comes from our config\session.php, looking in particular this line:

session.php

'cookie' => 'laravel_session', # ~~ ln 121 at time of writing

Ok, but that doesn't help a lot, changing this, changes it everywhere, as noted by the comment proceeding it in the config.

The name specified here will get used every time a new session cookie is created by the framework for every driver.

And even if we could pass it some dynamic value, something like:

'cookie' => 'laravel_session' . user()->id,

This creates a paradoxical, time ending, universe imploding outcome because you are requesting the id from the user which is accessed via the session looked up by the cookie name laravel_session.. (mindblown)

Let's leave SessionManager and it's session.php configuration alone. We can see from above that regardless of how we approach this, all our session info will be fall under that single laravel_session key.

Guard

Maybe Guard will have some more information.

Guard is your key to auth into your app, and one of the many things that makes Laravel awesome for quickly creating applications.

The method to look at is Guard::user().

One of the first things Guard::user() does after some initial cache and logged out checking, is a session check.

Guard::user()

$id = $this->session->get($this->getName()); 

So here, Laravel is fetching the session values that match the result of getName() - awesome - all we need to do is mod getName() to return a value, let's take a took at that method:

Guard::getName()

public function getName()
{
    return 'login_'.md5(get_class($this));
}

That's pretty straight forward. $this refers to the Guard class, so the md5 will effectively always be the same (if anyone knows the 'why' behind md5'ing the class name which would be the same each time, leave a comment).

There are a few places where this should be updated, such as getRecallerName.

So from here, you can extend the core Guard class and splice in your getName and getRecallerName methods.

You will probably want to wrap some service provider around this, write some unit tests, possibly even overwrite the original auth manager.

"Geez, that seems like a lot of work"

"It sure is Billy, it sure is"

https://www.youtube.com/watch?v=dTxQ9yhGnAg

See the next part

The quick "I just need an answer" answer

Ollie Read has already created a solution, found here:

https://github.com/ollieread/multiauth

I encourage you to have a look, especially the custom Guard class which extends core Guard with custom getName methods.