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方法能正确匹配:
- 测试时为用户添加
sub字段(可以在测试工厂中设置) - 调整
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
相关产品推荐
相关产品推荐

