来自同一浏览器的 Laravel 和多会话

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/33311771/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-14 12:34:09  来源:igfitidea点击:

laravel and multi-sessions from the same browser

phplaravellaravel-5

提问by JasonGenX

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?

在我们的 Web 应用程序中,如果我使用单个浏览器,请以用户 A 的身份登录到我们的应用程序,打开另一个选项卡并以用户 B 的身份登录 - 用户 A 会丢失他的会话数据。我认为这是由于用户代理创建的共享 cookie。有没有办法用用户名连接它的名字?以便会话可以在同一台机器上使用相同浏览器的并发登录用户之间共存?

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

我们使用 Laravel 5。有什么办法可以解决吗?

回答by Chris

Laravel Session Background

Laravel 会话背景

Sessions

会话

Skip this section for a quick easy solution

跳过此部分以获得快速简单的解决方案

In Laravel, session cookies are created via the Illuminate\Session\SessionManagerclass, namely through the buildSessionmethod:

在 Laravel 中,会话 cookie 是通过Illuminate\Session\SessionManager类创建的,即通过以下buildSession方法:

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:

在这个方法中,我们可以清楚地看到会话的名称来自我们的config\session.php,特别是这一行:

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.

每次框架为每个驱动程序创建新的会话 cookie 时,都会使用此处指定的名称。

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 idfrom the userwhich is accessed via the sessionlooked up by the cookiename laravel_session.. (mindblown)

这会产生一个矛盾的、时间结束的、宇宙崩溃的结果,因为您正在请求通过名称查找的idfrom .. (脑残)usersessioncookielaravel_session

Let's leave SessionManagerand it's session.phpconfiguration alone. We can see from above that regardless of how we approach this, all our session info will be fall under that single laravel_sessionkey.

让我们离开吧SessionManager,它是session.php单独的配置。我们可以从上面看到,无论我们如何处理,我们所有的会话信息都将归入该单个laravel_session密钥。

Guard

警卫

Maybe Guard will have some more information.

也许 Guard 会有更多的信息。

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

Guard 是您对应用程序进行身份验证的关键,也是使 Laravel 能够快速创建应用程序的众多因素之一。

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

看的方法是Guard::user()

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

Guard::user()在一些初始缓存和注销检查之后要做的第一件事就是会话检查。

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:

所以在这里,Laravel 正在获取与结果匹配的会话值getName()- Awesome - 我们需要做的就是 modgetName()返回一个值,让我们来看看这个方法:

Guard::getName()

守卫::getName()

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

That's pretty straight forward. $thisrefers 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).

这很直接。$this指的是 Guard 类,因此 md5 将有效地始终相同(如果有人知道 md5 背后的“为什么”每次都相同的类名,请发表评论)。

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

有几个地方应该更新它,例如getRecallerName.

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

因此,从这里开始,您可以Guard在 getName 和 getRecallerName 方法中扩展核心类和拼接。

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

“天哪,这似乎是很多工作”

“肯定是比利,肯定是”

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:

Ollie Read 已经创建了一个解决方案,可在此处找到:

https://github.com/ollieread/multiauth

https://github.com/ollieread/multiauth

I encourage you to have a look, especially the custom Guardclass which extends core Guardwith custom getNamemethods.

我鼓励您看一看,尤其是使用自定义方法Guard扩展核心的自定义类。GuardgetName

回答by Ryan Bemrose

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.

任何主流浏览器都只会为一个站点存储一个会话 cookie,但站点开发人员可以选择该 cookie 中的内容。您的站点似乎将用户信息存储在会话 cookie 中,然后当另一个选项卡将不同的信息存储在同一个 cookie 中时,会话 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.

1)为不同的用户使用不同的浏览器。不同的浏览器不会在它们之间共享 cookie。如果您的目标只是让多个用户测试您的网站,那么这就是方法。您还可以使用隐身/私密模式以单独的用户登录,因为此模式也不共享 cookie。

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.

2)不要使用会话 cookie 来存储用户信息。这在大多数网站上都不是初学者,但如果这是内部站点或严格控制的环境,您可能能够通过 URL、POST 数据或请求中的其他一些隐藏标识符传递用户标识。

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

3)将所有当前登录用户的数据存储在会话 cookie 中。根据 Web 框架的不同,可以创建一个user->的映射,cookieData并根据发出请求的用户查找正确的映射。这是一种高级技术,我实际上不知道 Laravel 是否公开了这种级别的控制。

回答by Alex Blex

tl;dr: Yagni

tl;博士:亚尼

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

考虑一个具有 2 个身份的人(在您的情况下为 http 客户端):Dr JekyllMr Hyde.
他拜访了他的新朋友先生RM1970(在你的例子中是 http 服务器):“你好吗,RM1970”。
这是问题所在。穷人RM1970需要欢迎怪物回来,选择很少:

  • fall deep into this rabbit hole: "How do you do both Dr Jekylland 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 singleidentity per request)
  • 陷入这个兔子洞:“你如何同时做Dr JekyllMr Hyde”,这使进一步的对话变得非常复杂(例如,你的 ACI 将需要处理身份列表,并在它们实时冲突时就优先级做出决定)
  • 自己做决定:“你好吗Dr Jekyll”并祈祷你做出了正确的选择(随机选择用户的身份,用不可预测的反应给你的用户带来一些乐趣)
  • 狡猾地把这个责任转给他:“原谅我?你是谁?说出你自己的名字!”(每个请求需要一个身份)

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.

后者是它的实际工作方式。浏览器提供最新确认的身份。
你被要求改变这一点,但你真的想要吗?坚守阵地,不要承担这个责任。
如果您不使用前 2 个死胡同选项,您将需要询问用户代表他发送请求的原因。这里最好的选择是让你的前端有状态,维护打开的会话列表,并提供一个用户界面供用户选择。这几乎是 Ryan Bemrose 的第三个选项,但是将这些数据存储在客户端,并且只发送选择的一个。无需更改 Laravel 后端。

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

一些浏览器支持多个配置文件(示例),这可能是一个可接受的替代方案。基本上它与第一个 Ryan Bemrose 的选项相同,但不需要安装多个浏览器,并且可以从永久 cookie 中受益,也就是“记住我”。

回答by Eric Kelly

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.

最简单的只是基于 URL 的 sessionID,这可能是一个安全问题,具体取决于您的应用程序的设计方式,尤其是在与未过期的会话共享 url 时。

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

由于 L5 不再支持 php 本机会话,因此您必须使用如下所示的自定义提供程序:

This will use sessionID in the url for laravel V5:

这将在 Laravel V5 的 url 中使用 sessionID:

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

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.

基本上,会话是基于 URL 的,因此您只需在不同的选项卡中登录并获得新的 sessionID,如果需要,该人也可以轻松执行“在新选项卡中打开页面”以拥有同一用户的两个页面。

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

上面的库将会话锁定到 IP 和用户代理,因此链接共享不会意外泄漏会话。

回答by Mitul

Multi userlogin with same browser like google add account. for that you need follow some steps and re-write auth library which provided by the Laravel,

多用户登录与谷歌一样的浏览器添加帐户。为此,您需要遵循一些步骤并重写 Laravel 提供的 auth 库,

Steps

脚步

Tack backup of your Auth file.

Change all session store functionality to store it first in array and then store that array to session

Now you need to create the new session variable which will store the current user instance id like user 0 1 2 ...

Now you need to change all the function from you will get the values from the session you need to check if the session object is empty then user is logout else you need to get data of the user base on the user instance.

You need to change your instance when user want to switch from one account to another.

备份您的 Auth 文件。

更改所有会话存储功能以先将其存储在数组中,然后将该数组存储到会话中

现在您需要创建新的会话变量,它将存储当前用户实例 ID,如 user 0 1 2 ...

现在您需要更改所有函数,您将从会话中获取值,您需要检查会话对象是否为空然后用户注销,否则您需要根据用户实例获取用户的数据。

当用户想要从一个帐户切换到另一个帐户时,您需要更改您的实例。

回答by Pawel Bieszczad

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 thisextension in chrome.

我不完全知道您需要它做什么,但作为开发人员,我有时必须登录多个用户的应用程序。为此,我通常使用隐身模式,或者如果它的用户超过 2 个,我在 chrome 中使用扩展程序很幸运。

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

我知道这不是您问题的答案,但它可能正是您要寻找的。

回答by ruibin

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_startis called,SessionID is created and then temp file is created in server's temporary directory.

并发登录用户之间的不同视图并存不能仅仅通过会话cookie来实现,因为cookie是由浏览器存储的。所以登录用户的seesion必须存储在Server上。众所周知,一旦 session_start被调用,就会创建SessionID,然后在服务器的临时目录中创建临时文件。

Diffent user has different SessionID and after session_destorycalled 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

不同的用户有不同的 SessionID,session_destory调用后恢复所有存储在 Server 和 Cookies 中的 SessionID。您可以通过实现 SessionHandlerInterface 来重写此行为。当然很多 web 框架都支持这个,Laravel 也不例外。这是文档: custom-session-drivers

回答by cre8

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

我不知道将它编码到 Laravel 中有多复杂,但这可能是一种解决方案:

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.

您使用不同的会话名称,必须是一个字符串,并且每次都将其编码到 url 中,以便应用程序知道哪个用户发出了请求。因此,您可以通过普通名称调用会话变量。

<?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'];