You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Laravel集成Auth0后PHPUnit测试登录状态丢失问题求解

问题:Laravel集成Auth0后PHPUnit测试中登录状态丢失

场景说明

Laravel应用带有标准User表,已集成Auth0登录功能,登录时会根据邮箱自动创建数据库用户记录。CustomUserRepository和auth配置均正常,生产环境功能符合预期,但在PHPUnit测试中出现异常:使用$this->be()登录后,第一个请求返回200正常,第二个请求(GET/POST)会重定向到登录页面,登录状态丢失。

相关代码

CustomUserRepository.php

<?php

namespace App\Repositories;

use App\Models\User;
use Illuminate\Contracts\Auth\Authenticatable;

class CustomUserRepository implements \Auth0\Laravel\Contract\Auth\User\Repository
{
    public function fromSession(array $user): ?\Illuminate\Contracts\Auth\Authenticatable
    {
        return User::firstOrCreate(['email' => $user['email']]);
    }

    public function fromAccessToken(array $user): ?\Illuminate\Contracts\Auth\Authenticatable
    {
        // Simliar to above. Used for stateless application types.
        return null;
    }

    public function getUserByUserInfo(array $userinfo) : Authenticatable
    {
        $user = $this->upsertUser( $userinfo['profile'] );
        return new Auth0User( $user->getAttributes(), $userinfo['accessToken'] );
    }

    protected function upsertUser($profile)
    {
        return User::firstOrCreate(
            [
                'sub' => $profile['sub']
            ],
            [
                'email' => $profile['email'] ?? '',
                'name' => $profile['name'] ?? '',
            ]
        );
    }
}

auth.php 配置

<?php

return [

    'defaults' => [
        'guard'     => 'auth0',
        'passwords' => 'users',
    ],

    'guards' => [
        'web' => [
            'driver'   => 'session',
            'provider' => 'users',
        ],
        'auth0' => [
            'driver' => 'auth0',
            'provider' => 'auth0',
        ],
    ],

    'providers' => [
        'users' => [
            'driver' => 'eloquent',
            'model'  => App\Models\User::class,
        ],
        'auth0' => [
            'driver' => 'auth0',
            'repository' => App\Repositories\CustomUserRepository::class
        ],
    ],
];

测试代码

$this->be(User::find(1));
$response = $this->get('/valid-url');
$response->assertStatus(200);

$response = $this->get('/another-valid-url');
$response->assertStatus(200);

问题原因

默认guard配置为auth0,而$this->be()方法默认使用当前默认guard。Auth0 guard的认证逻辑依赖于Auth0的会话数据,测试中直接传入Eloquent User模型,无法被Auth0 guard在后续请求中正确识别,导致登录状态无法保持。

解决方案

方案1:测试时指定使用web guard

修改测试代码,明确指定使用Laravel原生的web guard(基于会话的Eloquent认证),这样测试会话能正常保持登录状态:

// 指定web guard进行登录
$this->be(User::find(1), 'web');

$response = $this->get('/valid-url');
$response->assertStatus(200);

$response = $this->get('/another-valid-url');
$response->assertStatus(200);

方案2:修改测试环境的默认guard

在测试环境中,将默认guard改为web,避免每次测试都指定guard:

  • 可以在config/auth.php中通过环境变量配置:
'defaults' => [
    'guard'     => env('AUTH_GUARD', 'auth0'),
    'passwords' => 'users',
],
  • 然后在.env.testing中添加:
AUTH_GUARD=web

方案3:适配Auth0 guard的测试逻辑(可选)

如果需要在测试中使用Auth0 guard,需确保测试用户包含Auth0的sub字段,并且CustomUserRepository的fromSession方法能正确匹配:

  1. 测试时为用户添加sub字段(可以在测试工厂中设置)
  2. 调整fromSession方法同时匹配email和sub:
public function fromSession(array $user): ?\Illuminate\Contracts\Auth\Authenticatable
{
    return User::firstOrCreate(
        ['email' => $user['email'], 'sub' => $user['sub']],
        ['name' => $user['name'] ?? '']
    );
}

内容的提问来源于stack exchange,提问作者Andreas Christodoulou

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.10 17:01:08