Метод Illuminate\Auth\RequestGuard::logout не существует Laravel Passport

Я использую Laravel Passport для создания API я удалил веб-маршруты и их защиту соответственно

Как я могу проверить выход пользователя из системы?

Вот что у меня есть на данный момент:

Logout Test

/**
 * Assert users can logout
 *
 * @return void
 */
public function test_logout()
{
    // $data->token_type = "Bearer"
    // $data->access_token = "Long string that is a valid token stripped out for brevety"
    $response = $this->json('POST', '/api/logout', [], [
         'Authorization' => $data->token_type . ' ' . $data->access_token
    ]);
    $response->assertStatus(200);
}

routes/api.php

Route::post('logout', 'Auth\LoginController@logout')->name('logout');
Метод контроллера использует AuthenticatesUsers черта, поэтому функция по умолчанию сохраняется
/**
 * Log the user out of the application.
 *
 * @param  \Illuminate\Http\Request  $request
 * @return \Illuminate\Http\Response
 */
public function logout(Request $request)
{
    $this->guard()->logout();

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

    return $this->loggedOut($request) ?: redirect('/');
}

Метод ошибки Illuminate\Auth\RequestGuard::logout не существует

В документации Laravel говорится о выпуске и обновлении токенов доступа, но ничего не говорится об их отзыве или выполнении выхода.

Примечание: я использую токены предоставления пароля

Примечание 2: отмена токена пользователя не работает

public function logout(Request $request)
{
    $request->user()->token()->revoke();
    return $this->loggedOut($request);
}

Test Fails on second assertion

public function test_logout()
{
    $response = $this->json('POST', '/api/logout', [], [
         'Authorization' => $data->token_type . ' ' . $data->access_token
    ]);
    $response->assertStatus(200); // Passes
    $check_request = $this->get('/api/user');
    $check_request->assertForbidden(); // Fails
}

Учитывая маршрут по умолчанию, требующий аутентификации

Route::middleware('auth:api')->get('/user', function (Request $request) {
    return $request->user();
});

Код состояния ответа [200] не является запрещенным кодом состояния.

Так что же происходит? и как я могу проверить выход пользователя с помощью паспорта?

заранее спасибо

4 ответа

Решение

Отзыв токена работает. Это тест, который не работает, но непонятно почему.

При выполнении нескольких запросов в одном тесте состояние вашего приложения laravel не сбрасывается между запросами. Диспетчер аутентификации - это синглтон в контейнере laravel, и он хранит локальный кеш разрешенных средств защиты аутентификации. Разрешенные средства защиты аутентификации сохраняют локальный кеш авторизованного пользователя.

Итак, ваш первый запрос к вашему api/logout конечная точка разрешает диспетчер аутентификации, который разрешает api guard, который хранит ссылки на авторизованного пользователя, чей токен вы будете отзывать.

Теперь, когда вы делаете второй запрос к /api/user, уже разрешенный диспетчер аутентификации извлекается из контейнера, уже разрешенный api guard извлекается из его локального кеша, а тот же уже разрешенный пользователь извлекается из локального кеша Guard. Вот почему второй запрос проходит аутентификацию, а не терпит неудачу.

При тестировании материалов, связанных с аутентификацией, с помощью нескольких запросов в одном тесте вам необходимо сбросить разрешенные экземпляры между тестами. Кроме того, вы не можете просто отключить разрешенный экземпляр диспетчера аутентификации, потому что, когда он будет разрешен снова, у него не будет расширенногоpassport драйвер определен.

Итак, самый простой способ, который я нашел, - использовать отражение, чтобы отключить защищенный guardsсвойство в разрешенном диспетчере аутентификации. Вам также необходимо позвонить вlogout метод на разрешенном сеансе охранников.

У меня есть метод в моем классе TestCase, который выглядит примерно так:

protected function resetAuth(array $guards = null)
{
    $guards = $guards ?: array_keys(config('auth.guards'));

    foreach ($guards as $guard) {
        $guard = $this->app['auth']->guard($guard);

        if ($guard instanceof \Illuminate\Auth\SessionGuard) {
            $guard->logout();
        }
    }

    $protectedProperty = new \ReflectionProperty($this->app['auth'], 'guards');
    $protectedProperty->setAccessible(true);
    $protectedProperty->setValue($this->app['auth'], []);
}

Теперь ваш тест будет выглядеть примерно так:

public function test_logout()
{
    $response = $this->json('POST', '/api/logout', [], [
         'Authorization' => $data->token_type . ' ' . $data->access_token
    ]);
    $response->assertStatus(200);

    // Directly assert the api user's token was revoked.
    $this->assertTrue($this->app['auth']->guard('api')->user()->token()->revoked);

    $this->resetAuth();

    // Assert using the revoked token for the next request won't work.
    $response = $this->json('GET', '/api/user', [], [
         'Authorization' => $data->token_type . ' ' . $data->access_token
    ]);
    $response->assertStatus(401);
}

auth()->guard('веб')->logout()

с использованиемauth()->guard('web')->logout()иauth()->guard('web')->login($user)решил мою проблему, очень странно находить вводящие в заблуждение шаги в официальной документации.

Использовать:

      auth()->forgetGuards();

Принятый ответ не работал для меня. Наконец-то я заметил, что при отзыве токена пользователя и вызове resetAuth() из принятого ответа он работает:

      protected function resetAuth() {
    $this->app['auth']->guard('api')->user()->token()->revoke(); //Revoke (or delete()) the passport user token.
    //$this->app['auth']->guard('web')->logout(); //If you also want to call the logout function on your web guard. 
    $protectedProperty = new \ReflectionProperty($this->app['auth'], 'guards');
    $protectedProperty->setAccessible(true);
    $protectedProperty->setValue($this->app['auth'], []);
}

Но это вызвало исключение при использовании таких методов, как $this->isAuthenticated() -//League\OAuth2\Server\Exception\OAuthServerException: The resource owner or authorization server denied the request.

В конце концов я наткнулся:auth()->forgetGuards();который, кажется, помогает правильно очистить аутентификацию без каких-либо последующих проблем.

Другие вопросы по тегам