419注销和重新登录后Laravel中出现错误(多个选项卡)

419注销和重新登录后Laravel中出现错误(多个选项卡),laravel,csrf,Laravel,Csrf,我在我的Laravel应用程序中打开了两个选项卡 我在一个选项卡中单击“注销”。然后单击第二个选项卡中的“注销”。第二次logout用于给出419错误,但我将其添加到VerifyCsrfToken中间件的排除列表中。我不明白为什么我需要CSRF保护才能注销 但是,现在我有一个不同的问题 在两个选项卡中注销后,它们都位于登录页面上。现在,如果我尝试从第一个选项卡重新登录,就会出现419错误。从第二个选项卡,登录可以正常工作 我该怎么办?我不想在用户单击“登录”时向用户显示错误,这是糟糕的用户体验。

我在我的Laravel应用程序中打开了两个选项卡

我在一个选项卡中单击“注销”。然后单击第二个选项卡中的“注销”。第二次
logout
用于给出419错误,但我将其添加到
VerifyCsrfToken
中间件的排除列表中。我不明白为什么我需要CSRF保护才能注销

但是,现在我有一个不同的问题

在两个选项卡中注销后,它们都位于登录页面上。现在,如果我尝试从第一个选项卡重新登录,就会出现419错误。从第二个选项卡,登录可以正常工作

我该怎么办?我不想在用户单击“登录”时向用户显示错误,这是糟糕的用户体验。我也不想将登录路由排除在CSRF保护之外。

注意事项 在这个回答中,我将浏览器打开的选项卡命名为选项卡A选项卡B

只需考虑以下规则:

  • 您的浏览器一次对域有一个活动会话(使用会话id cookie访问)
  • 客户端:每个打开的选项卡都可以有一个CSRF标记,其形式为标题等
  • 服务器端:会话变量中只保存一个csrf令牌
  • 在每个post请求中,客户端和服务器令牌都应该匹配,否则会出现419错误
注销时CSRF保护的必要性 不,不需要在注销路由中防止CSRF保护,因为这不是一个资源更改路由。很高兴您
除了从CSRF保护中退出=['logout']

发生情景 1. 首先,您已经打开了选项卡AB,它们已登录并共享相同的会话和令牌

选项卡A-会话1-令牌x 选项卡B-会话1-令牌x

2. 单击选项卡A注销。它将从服务器上清除会话。重定向回登录页面。在登录页面中,客户端请求服务器,为他创建一个新的会话令牌

选项卡A-会话2-令牌y 选项卡B-会话2(会话id为“”的cookie用于域)-令牌x(客户端:在选项卡中显示/从服务器中删除,因为它在会话1中)

由于服务器端没有保存令牌x的会话1,因此选项卡B令牌与服务器的令牌y不匹配

3. 正在选项卡B上发送注销

如果您在启用csrf的情况下发送注销。中间件向您发送419,因为客户端上的令牌x和服务器上的令牌b之间存在误操作

如果其免于csrf,则它**清除服务器端的会话**,并将客户端重定向到登录页面,重定向后服务器使用新的csrf令牌为选项卡B创建一个新的会话

我想您可以在注销路径上免除csrf保护,然后继续第二个场景

选项卡A-会话3-令牌y 选项卡B-会话3-令牌z

如您所见,服务器具有会话3和令牌z。因此选项卡A不匹配

结论 正如您所看到的,出现这种错误有一些原因:

  • 会话(cookie)是浏览器范围,但令牌是选项卡范围
  • 用户在一个选项卡上做了一些事情,使得其他选项卡有一个错误处理其表单令牌的会话
因此,正如您所看到的,预防解决方案已经出现:

如果用户希望:

  • 打开多个选项卡
  • 注销(重新创建会话)在一个选项卡上
  • 继续使用其他打开的选项卡/表单(刷新可以解决此问题)
解决方案 您必须使会话和令牌范围同步

有两种解决方案:

  • 创建令牌浏览器范围:使用SPA客户端框架即可实现。(更可取)

  • 生成会话页面范围:

    • 将注销功能更改为不清除会话只清除响应会话\u id

    • 使用隐藏输入进行会话跟踪(其本身有向下的部分)(obsolote)

  • 我建议客户端使用单页应用程序框架

    考虑 在这个回答中,我将浏览器打开的选项卡命名为选项卡A选项卡B

    只需考虑以下规则:

    • 您的浏览器一次对域有一个活动会话(使用会话id cookie访问)
    • 客户端:每个打开的选项卡都可以有一个CSRF标记,其形式为标题等
    • 服务器端:会话变量中只保存一个csrf令牌
    • 在每个post请求中,客户端和服务器令牌都应该匹配,否则会出现419错误
    注销时CSRF保护的必要性 不,不需要在注销路由中防止CSRF保护,因为这不是一个资源更改路由。很高兴您
    除了从CSRF保护中退出=['logout']

    发生情景 1. 首先,您已经打开了选项卡AB,它们已登录并共享相同的会话和令牌

    选项卡A-会话1-令牌x 选项卡B-会话1-令牌x

    2. 单击选项卡A注销。它将从服务器上清除会话。重定向回登录页面。在登录页面中,客户端请求服务器,为他创建一个新的会话令牌

    选项卡A-会话2-令牌y 选项卡B-会话2(会话id为“”的cookie用于域)-令牌x(客户端:在选项卡中显示/从服务器中删除,因为它在会话1中)

    由于服务器端没有会话1,它持有令牌x,因此选项卡B令牌m