laravel and multi-sessions from the same browser

2019-01-17 03:53发布

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?

8条回答
迷人小祖宗
2楼-- · 2019-01-17 04:23

I don't exactly know what do you need this for, but as a developer I sometimes have to log into an application with multiple users. To do that I usually use incognito mode or if its more than 2 users I had some luck using this extension in chrome.

I know its not an answer to your question but it just might be what your looking for.

查看更多
贪生不怕死
3楼-- · 2019-01-17 04:25

The easiest is just a URL based sessionID which could be a security issue depending on how your application is designed, especially when sharing urls with non-expired sessions.

Since L5 doesn't support php native sessions anymore, you'll have to use a custom provider like below:

This will use sessionID in the url for laravel V5:

https://github.com/iMi-digital/laravel-transsid

Basically the session is URL based, so you can just login in a different tab and get a new sessionID, and that person can easily do a "open page in new tab" to have two pages of the same user if needed as well.

The library above locks the session to the IP and User Agent so link sharing won't accidentally leak a session.

查看更多
狗以群分
4楼-- · 2019-01-17 04:26

tl;dr: Yagni

Consider a person (http client in your case) with 2 identities: Dr Jekyll and Mr Hyde.
He visits his new friend Sir RM1970 (http server in your case): "How do you do, RM1970!".
Here is the problem. Poor RM1970 need to welcome back the monster, and there are few options:

  • fall deep into this rabbit hole: "How do you do both Dr Jekyll and Mr Hyde!", which incredibly complicates further conversation (your ACl, for example, will need to operate with list of identities, and make a decision about priorities if they conflict realtime)
  • make a decision on your own: "How do you do Dr Jekyll!" and pray you made the right choice (randomly pick user's identity and bring your users some fun with unpredictable responses)
  • be sly and shift this responsibility back to him: "Pardon me? Who are you? Name yourself!" (require single identity per request)

The later is how it actually works. The browser provides the latest confirmed identity.
You've been asked to change this, but do you really want it? Hold the line and don't accept this responsibility.
If you are not going with first 2 dead-end options, you will need to ask user on which behalf he sends the request. The best option here is to make your frontend stateful, maintain list of opened sessions, and provide a UI for user to pick one. It is almost the 3rd Ryan Bemrose's option, but store this data on client side, and send only the chosen one. No changes in laravel backend required.

The problem here is switching tabs will not automatically switch user, and will be rather confusing, providing very little difference with logout/login path, which is already implemented.

Some browsers support multiple profiles (example), which may be an acceptable alternative. Basically it is the same as 1st Ryan Bemrose's option, but does not require multiple browsers installed, and can benefit from permanent cookies, aka 'remember-me'.

查看更多
放荡不羁爱自由
5楼-- · 2019-01-17 04:27

Any major browser will only store one session cookie for a site, but the site developer gets to choose what's in that cookie. It seems like your site is storing user information in the session cookie, which is then getting overwritten when the other tab stores different information in the same cookie.

You don't provide much detail about how your specific site operates, but here are a few general ways of approaching this problem.

1) Use different browsers for different users. Different browsers don't share cookies between them. If your goal is simply to test your site with multiple users, this is the way. You can also use Incognito/Private mode to log in a separate user, as this mode doesn't share cookies either.

2) Don't use session cookies to store user information. This is a non-starter on most websites, but if this is an internal site or strictly controlled environment, you may be able to pass user identification via the URL, POST data, or some other hidden identifier in the request.

3) Store data in the session cookie for all currently logged in users. Depending on the web framework, it may be possible to create a map of user -> cookieData and look up the correct one based on which user is making the request. This is an advanced technique, and I don't actually know if Laravel exposes this level of control.

查看更多
地球回转人心会变
6楼-- · 2019-01-17 04:31

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.

查看更多
女痞
7楼-- · 2019-01-17 04:33

I don't know how complicate it is to code it into laravel but this could be one solution:

You use a different session name, has to be a string, and code it into the url every time so the application knows which user made a request. So you can call the session variables by a normal name.

<?php
if(isset($_GET['id']) && !empty($_GET['id']))
    session_name($_GET['id']);
session_start();

if(isset($_GET['user'])) {
    $_SESSION['user'] = $_GET['user'];
}

if(!empty($_SESSION['user']))
    echo "Hello ".$_SESSION['user'];
查看更多
登录 后发表回答