Метод 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('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();
который, кажется, помогает правильно очистить аутентификацию без каких-либо последующих проблем.