👌
Laravel Sanctumでログアウトができない
laravelのテストを実装していた際に、ログアウトができないことがありましたので、その部分の原因と解決方法を記述していこうと思います。
前提
- MacOS
- Docker
- Laravel Framework 8.83.23
- PHP 8.0.28
- Laravel Sanctum(SPA)
- Laravel Breeze(認証)
前提
ログアウト処理のテスト内でログアウト処理が正常に行われた場合でも、$this->assertGuest();
にてfalseが返ってきておりました。
詰まったところ
当初は以下のような形で作成しておりました。
ルーティング側
api.php
Route::post('login', [AuthenticatedSessionController::class, 'store'])->name('login');
Route::group(['middleware' => ['auth:sanctum']], function () {
Route::post('logout', [AuthenticatedSessionController::class, 'destroy'])->name('logout');
}
テスト側
protected function testLogout(): void
{
$this->assertAuthenticated();
$response = $this->post(route('logout'));
$response->assertStatus(Response::HTTP_OK);
$this->assertGuest();
}
しかし、これだと前提のようにログアウトのテストが上手く通りません。
解決方法
まず、ログインとログアウトのルーティングをweb
のミドルウェア内に入れるようにします。
api.php
Route::group(['middleware' => ['web']], function () {
Route::post('login', [AuthenticatedSessionController::class, 'store'])->name('login');
Route::post('logout', [AuthenticatedSessionController::class, 'destroy'])->name('logout');
});
そして、\Auth
ファサードを使用するときに、必ず\Auth::guard('web')
のような形で、webガード
を指定するようにします。
そして、テスト実行時も以下のようにweb
を設定してあげます。
$this->assertGuest('web');
参考記事
Method Illuminate\Auth\RequestGuard::attempt does not existというエラーが出る
こういうエラーが出るときは、おそらくLoginRequest
内などをチェックすると良いかもしれません。
LoginRequest.php
/**
* ログイン処理
*
* @return void
*
* @throws \Illuminate\Validation\ValidationException
*/
public function authenticate()
{
$this->ensureIsNotRateLimited();
// ログインに失敗したときの処理
if (! \Auth::attempt($this->only(User::USER_EMAIL_DB, User::USER_PASSWORD_DB), $this->boolean('remember'))) {
RateLimiter::hit($this->throttleKey());
// NOTE: この形にしないvue側でstatusが200として処理されてしまう
// FIXME: responseに何を詰めるべきか検討
// responseデータ
$data = [
'status' => Response::HTTP_UNAUTHORIZED,
'errors' => trans('auth.failed'),
];
throw new HttpResponseException(response()->json($data, Response::HTTP_UNAUTHORIZED));
}
RateLimiter::clear($this->throttleKey());
}
上記で、\Auth::attempt
になっておりますが、ここも以下のようにガードを設定してあげる必要があります。
\Auth::guard('web')->attempt()
Discussion