👌

Laravel Sanctumでログアウトができない

2023/03/25に公開

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