Я отримував цю помилку з Laravel Sanctum. Я виправив це, додавши \Illuminate\Session\Middleware\StartSession::class,
до api
групи середнього програмного забезпечення в Kernel.php, але пізніше я зрозумів, що це "спрацювало", оскільки api.php
замість цього були додані мої маршрути аутентифікації web.php
, тому Laravel використовував неправильний захист аутентифікації.
Я перемістив ці маршрути сюди, web.php
а потім вони почали правильно працювати з AuthenticatesUsers.php
ознакою:
Route::group(['middleware' => ['guest', 'throttle:10,5']], function () {
Route::post('register', 'Auth\RegisterController@register')->name('register');
Route::post('login', 'Auth\LoginController@login')->name('login');
Route::post('password/email', 'Auth\ForgotPasswordController@sendResetLinkEmail');
Route::post('password/reset', 'Auth\ResetPasswordController@reset');
Route::post('email/verify/{user}', 'Auth\VerificationController@verify')->name('verification.verify');
Route::post('email/resend', 'Auth\VerificationController@resend');
Route::post('oauth/{driver}', 'Auth\OAuthController@redirectToProvider')->name('oauth.redirect');
Route::get('oauth/{driver}/callback', 'Auth\OAuthController@handleProviderCallback')->name('oauth.callback');
});
Route::post('logout', 'Auth\LoginController@logout')->name('logout');
Я зрозумів, що проблема після отримання ще однієї дивної помилки RequestGuard::logout()
не існує.
Це дало мені зрозуміти, що мої власні аут-маршрути викликають методи з ознаки AuthenticationUsers, але я не використовував Auth::routes()
для цього. Тоді я зрозумів, що Laravel використовує веб-охорону за замовчуванням, і це означає, що маршрути повинні бути в routes/web.php
.
Ось як виглядають мої налаштування зараз із Sanctum та зв'язаним додатком Vue SPA:
Kernel.php
protected $middlewareGroups = [
'web' => [
\App\Http\Middleware\EncryptCookies::class,
\Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
\Illuminate\Session\Middleware\StartSession::class,
// \Illuminate\Session\Middleware\AuthenticateSession::class,
\Illuminate\View\Middleware\ShareErrorsFromSession::class,
\App\Http\Middleware\VerifyCsrfToken::class,
\Illuminate\Routing\Middleware\SubstituteBindings::class,
],
'api' => [
EnsureFrontendRequestsAreStateful::class,
\Illuminate\Routing\Middleware\SubstituteBindings::class,
'throttle:60,1',
],
];
Примітка. З Laravel Sanctum та з однодоменним Vue SPA ви використовуєте файли cookie httpOnly для сеансового файлу cookie та запам’ятайте мені cookie та незахищені файли cookie для CSRF, тому ви використовуєте web
охорону для auth та будь-який інший захищений маршрут, що повертається JSON, повинен використовувати auth:sanctum
проміжне програмне забезпечення.
config / auth.php
'defaults' => [
'guard' => 'web',
'passwords' => 'users',
],
...
'guards' => [
'web' => [
'driver' => 'session',
'provider' => 'users',
],
'api' => [
'driver' => 'token',
'provider' => 'users',
'hash' => false,
],
],
Тоді ви можете мати юнят тести , такі як це, де критично Auth::check()
, Auth::user()
і Auth::logout()
робота , як очікується , з мінімальною конфігурацією і максимальним використанням AuthenticatesUsers
і RegistersUsers
рисами.
Ось кілька моїх тестових одиниць реєстрації:
TestCase.php
/**
* Creates and/or returns the designated regular user for unit testing
*
* @return \App\User
*/
public function user() : User
{
$user = User::query()->firstWhere('email', 'test-user@example.com');
if ($user) {
return $user;
}
// User::generate() is just a wrapper around User::create()
$user = User::generate('Test User', 'test-user@example.com', self::AUTH_PASSWORD);
return $user;
}
/**
* Resets AuthManager state by logging out the user from all auth guards.
* This is used between unit tests to wipe cached auth state.
*
* @param array $guards
* @return void
*/
protected function resetAuth(array $guards = null) : void
{
$guards = $guards ?: array_keys(config('auth.guards'));
foreach ($guards as $guard) {
$guard = $this->app['auth']->guard($guard);
if ($guard instanceof SessionGuard) {
$guard->logout();
}
}
$protectedProperty = new \ReflectionProperty($this->app['auth'], 'guards');
$protectedProperty->setAccessible(true);
$protectedProperty->setValue($this->app['auth'], []);
}
LoginTest.php
protected $auth_guard = 'web';
/** @test */
public function it_can_login()
{
$user = $this->user();
$this->postJson(route('login'), ['email' => $user->email, 'password' => TestCase::AUTH_PASSWORD])
->assertStatus(200)
->assertJsonStructure([
'user' => [
...expectedUserFields,
],
]);
$this->assertEquals(Auth::check(), true);
$this->assertEquals(Auth::user()->email, $user->email);
$this->assertAuthenticated($this->auth_guard);
$this->assertAuthenticatedAs($user, $this->auth_guard);
$this->resetAuth();
}
/** @test */
public function it_can_logout()
{
$this->actingAs($this->user())
->postJson(route('logout'))
->assertStatus(204);
$this->assertGuest($this->auth_guard);
$this->resetAuth();
}
Я переосмислив registered
і authenticated
методи в ауто рисах Laravel, щоб вони повернули об'єкт користувача замість лише 204 ВАРІАНТІВ:
public function authenticated(Request $request, User $user)
{
return response()->json([
'user' => $user,
]);
}
protected function registered(Request $request, User $user)
{
return response()->json([
'user' => $user,
]);
}
Подивіться на код постачальника щодо авторських рис. Ви можете використовувати їх недоторканими, а також ці два вищевказані методи.
- vendor / laravel / ui / auth-backend / RegistersUsers.php
- vendor / laravel / ui / auth-backend / AuthenticationUsers.php
Ось мої дії Vue SPA для входу в систему:
async login({ commit }, credentials) {
try {
const { data } = await axios.post(route('login'), {
...credentials,
remember: credentials.remember || undefined,
});
commit(FETCH_USER_SUCCESS, { user: data.user });
commit(LOGIN);
return commit(CLEAR_INTENDED_URL);
} catch (err) {
commit(LOGOUT);
throw new Error(`auth/login# Problem logging user in: ${err}.`);
}
},
async logout({ commit }) {
try {
await axios.post(route('logout'));
return commit(LOGOUT);
} catch (err) {
commit(LOGOUT);
throw new Error(`auth/logout# Problem logging user out: ${err}.`);
}
},
Мені знадобилося більше тижня, щоб отримати Laravel Sanctum + однодоменний Vue SPA + авторизований тест, який працює на моєму рівні, тому, сподіваюся, моя відповідь тут може допомогти заощадити інший час у майбутньому.