从第三方网站POST后丢失会话数据

4
我有一个Laravel网站,会重定向到一个支付提供商(外部第三方网站)。当用户完成付款后,他们通过POST请求返回到我的网站。
我的问题是,当他们返回确认页面时,用户的会话丢失了。
我想知道这是否是PHP一般性的行为,但似乎是特定于Laravel的。
我已检查了sessions.php配置文件,并确认以下设置为'expire_on_close' => false。
我已创建了以下基本示例,以说明这个问题:
我的网站(售前)
控制器
public function redirect()
{
    $user = Auth::user();
    dd($user); // returns User model;
    redirect()->away('http://www.example.com');

}

支付提供者网站

请注意,请求是通过浏览器中的应用程序发送的,而不是回调。也没有按钮。我只是想演示 POST 返回到 Laravel 网站。

<html>
<head></head>
<body>

    <form method="POST" action="http://www.example.com/payment/confirmation">
        <input type="submit">
    </form>

</body>
</html>

我的网站(售后)

路线(Route)

Route::post('/payment/confirmation', 'Payment\PaymentController@confirmation');

控制器
public function confirmation()
{

    $user =  Auth::user();
    dd($user); // Returns null

}

我已经在VerifyCsrfToken中间件的异常数组中添加了路径。在通过外部网站进行POST请求时,有没有Laravel内置的东西会销毁会话?我肯定漏掉了一些明显的东西。谢谢。


请尝试使用Link Tracer扩展程序跟踪所有生命周期中的请求,并发布所有重定向的屏幕截图。 https://chrome.google.com/webstore/detail/link-redirect-trace/nnpljppamoaalgkieeciijbcccohlpoh/ - webzar
1
这很可能是由于在设置会话 cookie 时使用了不正确的 SameSite 值导致的。 - CBroe
这确实是由于config/session.php中的same_site设置引起的。将其设置为null即可解决问题。 - kinggs
4个回答

5
通过在config/session.php中将'same_site' => 'lax',更改为'same_site' => null,,我成功解决了此问题。这似乎是Laravel 7+中的新设置。目前我不确定此更改是否会产生任何安全影响,需要进一步阅读资料。但是,暂时来说这解决了问题。希望能够实现某种方式的白名单功能以允许特定域名。

4

设置“same_site” => null可能无法按预期工作,因为最近更改了与Cookie SameSite属性相关的标准。https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie/SameSite

新的默认值现在是Lax,因此,如果将same_site设置为null,则浏览器将假定默认值为Lax,这不是您需要的策略。

您需要明确设置'same_site' => "none",same_site的值为none需要您的连接是安全的,因此请将'secure' => true设置为true。

'same_site' => "none"
'secure' => true

1

您应该将cookie会话保持为“lax”,这样您的cookie就不会在其他网站上可用。

我发现的解决方法是在登录时传递true以记住登录状态。

例如:

Auth::login(
   user: $user,
   remember: true
);

$request->session()->regenerate();

您的用户现在将无限期登录,直到他们注销,即通过重定向标头等离开您的网站并返回。我发现这一点是在使用Passport接收Oauth回调时需要在那一点上登录用户,但需要将其重定向到其租户的子域。

通常,您只需要在config/env中像.mydomain.com这样设置会话可在根域和子域之间使用。


谢谢你的提示,设置登录时记住用户可以解决我的问题,并保持默认配置。在我的情况下,我的Laravel应用程序接收了一个外部POST请求,它总是销毁已经登录到应用程序中的用户的会话。 - Rubens

1
在我的测试中,似乎会话并没有被真正销毁。但是,在接收到外部POST请求时不会被加载,并且如果您允许返回主站点以触发新的会话保存,则会话将被销毁。通过发送一个header()重定向并在新会话可以保存之前终止进程,似乎可以恢复现有会话。
好吧,也许有点粗糙?
Route::match(['get','post'],'/payment/confirmation','Payment\PaymentController@confirmation');

public function confirmation(Request $request)
{
    // assert cookie or reload current URL
    if (! $request->hasHeader('Cookie')) {
        header('Location: '.url()->current());
        exit;
    }

    $user = Auth::user();
    dd($user); // user exists!
}

我不会说这是一个很好的解决方案。它感觉有点像黑客行为。可能需要进行一些额外的测试。但是乍一看,它似乎可以工作 - 至少在我的端上。也许它能够提供一些有关幕后实际情况的额外见解。
此外,我真的不确定您是否希望将付款确认页面公开到GET请求中。
但是,这是一个有趣的兔子洞,值得一探究竟。

谢谢您的回答。我通过更改config/session.php中的same_site设置来解决了这个问题。 - kinggs
有趣。这对我来说是新鲜事。我得去看看。谢谢。 - matticustard

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接