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

Losing session data after POST from third party website

我有一个 Laravel 网站可以重定向到支付提供商(外部第三方网站)。当用户完成付款后,他们将通过 POST 请求重定向回我的网站。

我遇到的问题是,当用户 return 进入确认页面时,他们的会话丢失了。

我想知道这是否是 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>

我的网站(post-促销)

路线

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

控制器

public function confirmation()
{

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

}

我已将路径添加到 VerifyCsrfToken 中间件的异常数组。 Laravel 中是否有任何东西会破坏通过外部网站在 POST 上的会话?我确定我遗漏了一些明显的东西。谢谢

在我的测试中,会话似乎并没有真正被销毁。但是在接收到外部POST请求时不会加载,如果允许return到主站触发新的session会被销毁会话保存。通过发送 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!
}

我不会说这是一个很好的解决方案。确实感觉有点hackish。可能需要进行一些额外的测试。但乍一看,它似乎确实有效——至少对我而言是这样。也许它可以让您深入了解幕后实际发生的事情。

此外,我不确定您是否要将付款确认页面公开给 GET 请求。

但这是一个有趣的兔子洞。

我通过在 config/session.php 中将 'same_site' => 'lax', 更改为 'same_site' => null, 解决了这个问题。这似乎是 Laravel 7+ 中的新设置。

在没有进一步阅读的情况下,我不确定此更改是否会导致任何安全隐患,但目前,这可以解决问题。以某种方式将某些域列入白名单将是一个不错的功能。

设置 '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' => 真。

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

您应该将您的 cookie session 保留到 'lax',您不希望您的 cookie 在其他网站上可用,等等。

我发现的修复方法是在登录时传递 true 以记住。

示例:

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

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

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

通常您只希望 session 在您的根域和子域中可用,例如 config/env.

中的 .mydomain.com