Saya mendapatkan kesalahan ini dengan Laravel Sanctum. Saya memperbaikinya dengan menambahkan \Illuminate\Session\Middleware\StartSession::class,
ke api
grup middleware di Kernel.php, tetapi saya kemudian menemukan bahwa ini "berfungsi" karena rute otentikasi saya ditambahkan api.php
sebagai ganti web.php
, jadi Laravel menggunakan penjaga auth yang salah.
Saya memindahkan rute ini ke sini web.php
dan kemudian mereka mulai bekerja dengan benar dengan AuthenticatesUsers.php
sifat:
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');
Saya menemukan masalah setelah saya mendapat kesalahan aneh lainnya tentang RequestGuard::logout()
tidak ada.
Itu membuat saya menyadari bahwa rute autentikasi khusus saya memanggil metode dari sifat AuthenticatesUsers, tetapi saya tidak menggunakannya Auth::routes()
untuk mencapainya. Kemudian saya menyadari Laravel menggunakan penjaga web secara default dan itu berarti rute harus masuk routes/web.php
.
Seperti inilah pengaturan saya sekarang dengan Sanctum dan aplikasi Vue SPA yang terpisah:
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',
],
];
Catatan: Dengan Laravel Sanctum dan Vue SPA domain yang sama, Anda menggunakan cookie httpOnly untuk cookie sesi, dan ingat saya cookie, dan cookie tidak aman untuk CSRF, jadi Anda menggunakan web
penjaga untuk auth, dan setiap rute yang dilindungi lainnya, JSON-return harus menggunakan auth:sanctum
middleware.
config / auth.php
'defaults' => [
'guard' => 'web',
'passwords' => 'users',
],
...
'guards' => [
'web' => [
'driver' => 'session',
'provider' => 'users',
],
'api' => [
'driver' => 'token',
'provider' => 'users',
'hash' => false,
],
],
Maka Anda dapat memiliki unit test seperti ini, di mana kritis, Auth::check()
, Auth::user()
, dan Auth::logout()
bekerja seperti yang diharapkan dengan konfigurasi minimal dan penggunaan maksimal AuthenticatesUsers
dan RegistersUsers
sifat.
Berikut adalah beberapa pengujian unit login saya:
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();
}
Saya mengganti registered
dan authenticated
metode dalam sifat autentikasi Laravel sehingga mereka mengembalikan objek pengguna, bukan hanya 204 OPTIONS:
public function authenticated(Request $request, User $user)
{
return response()->json([
'user' => $user,
]);
}
protected function registered(Request $request, User $user)
{
return response()->json([
'user' => $user,
]);
}
Lihat kode vendor untuk mengetahui ciri-ciri autentikasi. Anda dapat menggunakannya tanpa tersentuh, ditambah dua metode di atas.
- vendor / laravel / ui / auth-backend / RegistersUsers.php
- vendor / laravel / ui / auth-backend / AuthenticatesUsers.php
Berikut adalah tindakan Vuex Vue SPA saya untuk login:
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}.`);
}
},
Saya membutuhkan waktu lebih dari seminggu untuk mendapatkan tes unit autentikasi Laravel Sanctum + Vue SPA + domain yang sama semuanya bekerja sesuai standar saya, jadi semoga jawaban saya di sini dapat membantu menghemat waktu orang lain di masa mendatang.