laravel and multi-sessions from the same browser

后端 未结 8 1212
眼角桃花
眼角桃花 2020-12-02 21:00

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

相关标签:
8条回答
  • 2020-12-02 21:13

    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.

    0 讨论(0)
  • 2020-12-02 21:16

    Different seesions coexist between concurrent logged in users cannot just only implemented by session cookie,because cookie is stored by browser. So the logged in user's seesion must be stored by Server. As all we know, Once session_start is called,SessionID is created and then temp file is created in server's temporary directory.

    Diffent user has different SessionID and after session_destory called then all SessionIDs stored in Server and Cookies are recovered. You can rewrite this behavior by implementing SessionHandlerInterface. Of cause many web framework support this,Laravel has not exception. Here is the document: custom-session-drivers

    0 讨论(0)
  • 2020-12-02 21:22

    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'.

    0 讨论(0)
  • 2020-12-02 21:23

    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.

    0 讨论(0)
  • 2020-12-02 21:23

    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.

    0 讨论(0)
  • 2020-12-02 21:28

    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'];
    
    0 讨论(0)
提交回复
热议问题