Redirect login
Guest yang membuka URL panel akan diarahkan ke suatu halaman, sedangkan pengguna yang sudah login dan masuk ke dashboard aplikasi akan diarahkan ke tempat lain. Ada dua redirect dengan arah berlawanan, keduanya diregistrasikan oleh package ini dan keduanya dapat dioverride. Gunakan halaman ini ketika guest masuk ke halaman login yang salah, setelah login tidak masuk ke panel, atau ketika redirectGuestsTo() yang Anda tulis tidak lagi berlaku.
Periksa kedua function secara langsung
Kedua redirect tidak membutuhkan browser untuk direproduksi. Keduanya adalah static method yang menerima request dan mengembalikan URL atau null, sehingga jawabannya dapat diperiksa melalui tinker sebelum menyimpulkan ada masalah middleware:
use Illuminate\Http\Request;
use PandaPanel\Support\PanelHomeRedirect;
use PandaPanel\Support\PanelLoginRedirect;
// Where a guest opening /admin/users is sent.
PanelLoginRedirect::for(Request::create('/admin/users'));
// 'https://example.test/admin/login', or 'https://example.test/login', or null
// Where a signed-in user landing on /dashboard is sent.
$request = Request::create('/dashboard');
$request->setUserResolver(static fn () => $user);
PanelHomeRedirect::for($request);
// '/admin', or null to change nothing2
3
4
5
6
7
8
9
10
11
12
13
14
Jika salah satunya mengembalikan null, artinya bukan redirect ini yang memindahkan browser. Dengan begitu pencarian dapat dipersempit ke route aplikasi, Fortify, atau auth middleware.
| Hasil | Artinya |
|---|---|
PanelLoginRedirect::for() mengembalikan login milik panel | Panel memiliki halaman login sendiri dan route-nya terdaftar |
PanelLoginRedirect::for() mengembalikan route('login') | Request bukan milik panel, atau panel tidak pernah memanggil login() |
PanelLoginRedirect::for() mengembalikan null | Aplikasi tidak memiliki route login — response akan menjadi 401 |
PanelHomeRedirect::for() mengembalikan null | Salah satu dari lima kondisi di bawah tidak terpenuhi |
1. Guest masuk ke login aplikasi, bukan login panel
Penyebab. Panel tidak pernah memanggil login(). PanelLoginRedirect memeriksa Panel::hasLogin(), dan panel tanpa login sendiri juga tidak memiliki route login tujuan — sehingga hasilnya fallback ke route('login'), sama seperti perilaku Laravel tanpa package ini.
use PandaPanel\Core\Panel;
use PandaPanel\Core\PanelProvider;
final class AdminPanelProvider extends PanelProvider
{
public function panel(Panel $panel): Panel
{
return $panel
->path('admin')
->auth()
->login();
}
}2
3
4
5
6
7
8
9
10
11
12
13
php artisan route:list --name=panel.admin.authGET admin/login panel.admin.auth.loginpanel('admin')->hasLogin(); // true — what PanelLoginRedirect asks
panel('admin')->routeName('auth.login'); // 'panel.admin.auth.login'2
Empat toggle untuk front door berikut semuanya nonaktif secara default dan masing-masing memiliki reader:
| Method | Signature | Reader | Route yang diregistrasikan |
|---|---|---|---|
login | login(bool $login = true): self | hasLogin(): bool | panel.{id}.auth.login |
registration | registration(bool $registration = true): self | hasRegistration(): bool | panel.{id}.auth.register |
passwordReset | passwordReset(bool $passwordReset = true): self | hasPasswordReset(): bool | panel.{id}.auth.password.request, .password.reset |
emailVerification | emailVerification(bool $emailVerification = true): self | hasEmailVerification(): bool | panel.{id}.auth.verification.notice |
login() adalah gerbang untuk tiga fitur lainnya: PanelRouteRegistrar::registerAuth() langsung berhenti ketika hasLogin() bernilai false, sehingga panel yang meminta registration tanpa login tidak mendapatkan kedua route tersebut.
2. Guest masuk ke login panel, tetapi panel yang salah
Penyebab. PanelManager::resolveFromRequest() menentukan URL milik panel mana, dengan mengurutkan kandidat berdasarkan path terpanjang terlebih dahulu, kemudian mempertimbangkan domain().
use PandaPanel\Core\PanelManager;
app(PanelManager::class)->resolveFromRequest(Request::create('/admin/reports/weekly'))?->getId();
// 'reports' — the panel at /admin/reports wins over the one at /admin2
3
4
public function resolveFromRequest(Request $request): ?PanelPanel yang memiliki domain() dilewati untuk request pada host yang berbeda, sehingga dua panel dengan path yang sama pada dua domain tetap terpisah. Proses ini tidak membaca route — hanya host dan path — sehingga hasilnya tetap sama bahkan untuk URL yang sama sekali tidak memiliki route.
3. Guest mendapatkan 401 tanpa redirect
Penyebab. PanelLoginRedirect::for() mengembalikan null, dan package ini tidak menciptakan perilaku baru untuk redirect bernilai null. Illuminate\Auth\Middleware\Authenticate melempar AuthenticationException, lalu handler Laravel mengembalikan response()->noContent(401).
Ada dua kondisi yang menghasilkan null:
$panel = app(PanelManager::class)->resolveFromRequest($request);
if ($panel === null || ! $panel->hasLogin()) {
return Route::has('login') ? route('login') : null; // ← the application has no login route
}
$login = $panel->routeName('auth.login');
return Route::has($login) ? route($login) : null; // ← the panel's login route is not registered2
3
4
5
6
7
8
9
Kedua pemeriksaan Route::has() penting. Pemeriksaan kedua mencakup panel yang login()-nya dinonaktifkan setelah boot, serta aplikasi dengan register_routes => false, ketika route panel tidak tersedia untuk dijadikan tujuan redirect.
Request yang mengharapkan JSON tidak pernah menggunakan callback tersebut: Authenticate memberikan null, dan handler mengembalikan 401 beserta pesannya.
4. redirectGuestsTo() milik aplikasi tidak lagi berlaku
Penyebab. Service provider meregistrasikan PanelLoginRedirect melalui hook afterResolving(Kernel::class), yang berjalan setelah default framework dan setelah konfigurasi apa pun yang dilakukan provider aplikasi sebelumnya. Urutan ini disengaja agar redirect panel tidak hilang selama boot, tetapi konsekuensinya aturan aplikasi yang sudah ditulis sebelumnya juga dapat tertimpa.
// PandaPanelServiceProvider::registerGuestRedirect()
$redirect = static function (): void {
Authenticate::redirectUsing(PanelLoginRedirect::for(...));
AuthenticationException::redirectUsing(PanelLoginRedirect::for(...));
};
if ($this->app->resolved(Kernel::class)) {
$redirect();
}
$this->app->afterResolving(Kernel::class, $redirect);2
3
4
5
6
7
8
9
10
11
Perbaikan. Nonaktifkan registrasi otomatis dan panggil helper panel dari aturan Anda sendiri. Dengan begitu login panel tetap bekerja berdampingan dengan kebutuhan aplikasi:
// config/panda-panel.php
'register_guest_redirect' => false,2
// bootstrap/app.php
use Illuminate\Foundation\Configuration\Middleware;
use PandaPanel\Support\PanelLoginRedirect;
->withMiddleware(function (Middleware $middleware): void {
$middleware->redirectGuestsTo(
static fn ($request) => PanelLoginRedirect::for($request) ?? route('welcome'),
);
})2
3
4
5
6
7
8
9
redirectGuestsTo() adalah tempat yang didukung untuk menentukan perilaku ini dan menjadi keputusan terakhir. Mematikan config key tanpa menulis pengganti membuat default Laravel tetap berlaku: semua guest, termasuk yang membuka panel dengan login sendiri, diarahkan ke route('login').
redirectGuestsTo() juga mengarahkan Illuminate\Session\Middleware\AuthenticateSession::redirectUsing() ke callback yang sama. Package hanya mengatur dua callback yang ditunjukkan di atas; aplikasi yang menggunakan AuthenticateSession dan juga menginginkan redirect yang memahami panel perlu meregistrasikan bagian tersebut sendiri.
5. Setelah login tetap masuk ke /dashboard milik starter kit
Penyebab. Request tersebut ditangani oleh PandaPanel\Http\Middleware\RedirectPanelHome, dan PanelHomeRedirect::for() mengembalikan null. Ada lima kondisi yang menghasilkan null; periksa dalam urutan berikut:
| Kondisi | Pemeriksaan |
|---|---|
Fitur nonaktif, atau paths kosong | config('panda-panel.home_redirect') |
| Path tidak cocok dengan pattern mana pun | pattern Request::is(), tanpa slash di depan |
| Request sudah berada di dalam panel | panel menjawab URL miliknya sendiri; redirect di sini akan membuat loop |
| Tidak ada panel yang dapat diakses user | PandaPanel\Facades\PandaPanel::firstAccessibleTo($user) bernilai null |
Route dashboard milik panel tidak tersedia | register_routes nonaktif |
// config/panda-panel.php
'home_redirect' => [
'enabled' => true,
'paths' => ['dashboard'],
],2
3
4
5
6
| Key | Tipe | Default | Perilaku |
|---|---|---|---|
home_redirect.enabled | bool | true | Dibandingkan menggunakan !== true, sehingga value selain boolean true menonaktifkannya |
home_redirect.paths | list<string> | ['dashboard'] | pattern Request::is(); value non-string dan entry kosong dibuang |
Middleware-nya sengaja dibuat sempit:
public function handle(Request $request, Closure $next): Response
{
if (! $request->isMethod('GET') || $request->expectsJson()) {
return $next($request);
}
$target = PanelHomeRedirect::for($request);
return $target === null
? $next($request)
: redirect()->to($target);
}2
3
4
5
6
7
8
9
10
11
12
Hanya GET, dan tidak pernah berlaku untuk request yang mengharapkan JSON — sehingga API atau form POST yang kebetulan menggunakan path serupa tetap berjalan seperti sebelumnya.
Pengguna yang sudah login tetapi tidak diizinkan masuk ke panel mana pun tetap melihat halaman aplikasi tanpa perubahan. Tidak ada error dan tidak ada 403; redirect hanya tidak terjadi. Panel yang dianggap "pertama" ditentukan oleh PanelManager::firstAccessibleTo(), yang membaca PanelRegistry::all() — diurutkan berdasarkan panel id — lalu memilih panel pertama yang isAccessibleTo()-nya true.
use PandaPanel\Facades\PandaPanel;
PandaPanel::firstAccessibleTo($user)?->getId(); // 'admin'2
3
6. /dashboard memang halaman aplikasi dan sekarang tidak dapat diakses
Perbaikan. Nonaktifkan redirect. Route, nama route, dan page component Anda tidak pernah diubah — request hanya dijawab lebih awal oleh middleware web.
'home_redirect' => ['enabled' => false],Atau serahkan bagian lain menggunakan pattern:
'home_redirect' => ['enabled' => true, 'paths' => ['reports/*']],Atau hapus middleware package dari group web, yang juga berarti ResetPanelContext, ShareFlashToast, dan SharePanelData tidak lagi diregistrasikan dan Anda harus menambahkan keempatnya sendiri:
'register_web_middleware' => false,php artisan panel:install menampilkan informasi bahwa redirect ini aktif, karena redirect yang tidak diketahui developer akan mudah menjadi bug report:
INFO Signed-in visitors to /dashboard now land in the panel. Set home_redirect.enabled to
false in config/panda-panel.php to keep your own.2
7. Pengguna yang sudah login langsung dilempar keluar dari panel
Ada tiga middleware yang dapat memindahkan pengguna yang sudah login dari halaman panel, dan masing-masing memiliki tujuan berbeda. Baca header Location alih-alih menebak:
| Dikirim ke | Middleware | Penyebab |
|---|---|---|
verification.notice milik aplikasi | verified milik Laravel | ->auth() menambahkannya secara default dan akun belum terverifikasi |
panel.{id}.pages.settings-security | PandaPanel\Http\Middleware\RequireTwoFactor | panel memanggil requireTwoFactor() dan akun belum memiliki second factor |
panel.{id}.auth.two-factor.challenge | PandaPanel\Http\Middleware\RequireEmailCode | akun mengaktifkan emailed code dan session ini belum menyelesaikan challenge |
public function auth(bool $verified = true): self$panel->auth(); // appends ['auth', 'verified']
$panel->auth(verified: false); // appends ['auth'] only2
verified adalah middleware Laravel dan mengarahkan ke route verification.notice milik aplikasi, bukan ke panel.{id}.auth.verification.notice, yang merupakan nama route berbeda. Aplikasi tanpa route verification.notice akan mendapatkan RouteNotFoundException, bukan redirect. Gunakan auth(verified: false) ketika panel tidak membutuhkan gate tersebut.
Kedua middleware milik panel sendiri tidak dapat menghasilkan loop karena desainnya:
RequireTwoFactormembiarkan request lewat jika route security page panel tidak tersedia (Route::has()bernilai false), dan mengecualikan security page serta semua routepages.*lainnya — sehingga selalu tersedia tempat untuk menyelesaikan requirement yang diminta.RequireEmailCodemembiarkan request lewat jika challenge route tidak tersedia dan mengecualikan semua routeauth.two-factor.*; jika tidak, halaman untuk menjawab challenge justru akan diblokir oleh challenge itu sendiri. Middleware juga menyimpanurl.intendedterlebih dahulu, sehingga setelah berhasil pengguna kembali ke tujuan semula.
8. POST login berhasil tetapi halaman berikutnya kembali menjadi login
Package ini tidak terlibat. Halaman login panel melakukan POST ke endpoint milik Fortify — panel hanya memiliki tampilan login. Jika POST berhasil tetapi request berikutnya kembali menjadi guest, berarti session tidak bertahan melewati redirect. Periksa SESSION_DRIVER, SESSION_DOMAIN, dan SESSION_SECURE_COOKIE terhadap scheme serta host yang benar-benar dibuka, lalu periksa storage yang digunakan session driver.
Halaman auth milik panel diregistrasikan di luar auth middleware panel, menggunakan Panel::getBaseMiddleware() ditambah ResolvePanel, sehingga halaman login itu sendiri tidak pernah berada di belakang auth dan tidak mungkin menjadi penyebab loop.
$panel->getBaseMiddleware(); // ['web'] by default — session, CSRF, Inertia
$panel->getAuthMiddleware(); // ['auth', 'verified'] after auth()
$panel->getMiddleware(); // both, deduplicated, in that order2
3
9. /login, /register, atau /forgot-password milik panel mengembalikan 404
| URL | Mengembalikan 404 ketika |
|---|---|
{path}/login | login() tidak pernah dipanggil, atau register_routes bernilai false |
{path}/register | registration() nonaktif — PanelAuthController::register() memanggil abort_unless($this->panel()->hasRegistration(), 404) |
{path}/forgot-password, {path}/reset-password/{token} | passwordReset() nonaktif |
{path}/verify-email | emailVerification() nonaktif |
Pemeriksaan pada level route dan controller dibuat konsisten, sehingga mematikan flag setelah route:cache tetap menghasilkan 404, bukan merender halaman yang form-nya mengarah ke route yang tidak ada.
php artisan route:list --name=panel.
php artisan route:clear && php artisan route:cache2
Seluruh API yang dibahas di halaman ini
PandaPanel\Support\PanelLoginRedirect
public static function for(Request $request): ?stringuse PandaPanel\Support\PanelLoginRedirect;
PanelLoginRedirect::for($request); // string|null
PanelLoginRedirect::for(...); // first-class callable, which is how it is registered2
3
4
| Request | Hasil |
|---|---|
Di dalam panel yang memanggil login() | route('panel.{id}.auth.login'), absolute |
| Di dalam panel yang tidak memanggilnya | route('login') jika aplikasi memilikinya |
| Di luar semua panel | route('login') jika aplikasi memilikinya |
| Kedua route tidak ada | null |
PandaPanel\Support\PanelHomeRedirect
public static function for(Request $request): ?stringURL yang dikembalikan bersifat relative — route($route, absolute: false) — karena tujuan adalah halaman dalam aplikasi yang sama, dan relative target memungkinkan Inertia visit mengikutinya tanpa full reload. Guest redirect mengembalikan URL absolute untuk alasan yang berlawanan: tujuan secara sah dapat berada pada panel di domain lain.
PandaPanel\Http\Middleware\RedirectPanelHome
public function handle(Request $request, Closure $next): ResponseMiddleware ini ditambahkan ke group web oleh service provider, sebelum ResetPanelContext, ShareFlashToast, dan SharePanelData, karena request yang sudah dijawab olehnya tidak pernah mencapai layar panel dan tidak memiliki props yang perlu dibagikan.
Config key
| Key | Default | Efek |
|---|---|---|
register_guest_redirect | true | Meregistrasikan PanelLoginRedirect pada Authenticate dan AuthenticationException |
home_redirect.enabled | true | Menentukan apakah RedirectPanelHome melakukan sesuatu |
home_redirect.paths | ['dashboard'] | Pattern Request::is() yang diambil alih |
register_web_middleware | true | Menentukan apakah empat middleware web ditambahkan |
register_routes | true | Menentukan apakah route group panel tersedia sebagai tujuan redirect |
Member panel
| Member | Signature |
|---|---|
auth | auth(bool $verified = true): self |
login | login(bool $login = true): self |
hasLogin | hasLogin(): bool |
registration / hasRegistration | registration(bool $registration = true): self / hasRegistration(): bool |
passwordReset / hasPasswordReset | passwordReset(bool $passwordReset = true): self / hasPasswordReset(): bool |
emailVerification / hasEmailVerification | emailVerification(bool $emailVerification = true): self / hasEmailVerification(): bool |
requireTwoFactor / requiresTwoFactor | requireTwoFactor(bool $required = true): self / requiresTwoFactor(): bool |
routeName | routeName(string $name): string |
getRouteNamePrefix | getRouteNamePrefix(): string — panel.{id}. |
isAccessibleTo | isAccessibleTo(?Authenticatable $user): bool |
getBaseMiddleware / getAuthMiddleware / getMiddleware | masing-masing (): list<string> |
Member manager
| Member | Signature |
|---|---|
resolveFromRequest | resolveFromRequest(Request $request): ?Panel |
firstAccessibleTo | firstAccessibleTo(?Authenticatable $user): ?Panel |
Mengujinya
it('sends a guest to this panel\'s door, keeping where they were going', function (): void {
$this->get('/door')->assertRedirect('/door/login');
expect(session('url.intended'))->toContain('/door');
});
it('sends a signed-in user from the starter kit dashboard into their panel', function (): void {
$this->actingAs(User::factory()->admin()->create())
->get('/dashboard')
->assertRedirect('/admin');
});
it('leaves a guest to the application own auth', function (): void {
// Not this package's redirect: /dashboard is behind `auth`.
$this->get('/dashboard')->assertRedirect(route('login'));
});2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
use Illuminate\Support\Facades\Config;
Config::set('panda-panel.home_redirect.enabled', false);
$this->actingAs($admin)->get('/dashboard')->assertOk();2
3
4
5
Hal yang perlu diperhatikan
- Kedua config flag dibandingkan dengan
!== true. String'true'dari environment variable justru menonaktifkan fitur, bukan mengaktifkannya. - Pattern
home_redirect.pathstidak menggunakan slash di depan.'/dashboard'tidak cocok dengan apa pun;$request->is()membandingkan terhadap path yang sudah dipangkas. - Home redirect berjalan pada setiap GET yang cocok, bukan hanya sesaat setelah login. Bookmark
/dashboardjuga akan diarahkan ke panel; biasanya memang itu tujuannya, tetapi bisa mengejutkan jika tidak disadari. - Ini bukan post-login redirect milik Fortify. Fortify tetap mengirim user ke tujuan berdasarkan konfigurasi Fortify sendiri;
RedirectPanelHomemenangkap request ketika user sampai di sana. Package tidak mengubahhomemilik Fortify, sehingga mematikan config key mengembalikan layar starter kit persis seperti semula. - Pengguna yang sudah login tetapi gagal dalam access check panel mendapatkan 403, bukan redirect. Menaruh panel di belakang login bukan access control — lihat response 403.
login()pada panel publik menghasilkan halaman login yang tidak dibutuhkan. Halaman tersebut diregistrasikan hanya berdasarkanhasLogin(), sehingga panel yang mengosongkan auth stack denganauthMiddleware([])tetap bisa memiliki URL/login.- Halaman reset password milik panel bukan URL yang digunakan email reset. Notification
ResetPasswordmilik Laravel membangun URL dari routepassword.resetmilik aplikasi; mengarahkannya ke panel dilakukan melaluiResetPassword::createUrlUsing()di provider aplikasi Anda. firstAccessibleTo()membaca panel berdasarkan urutan id, bukan urutan config. Mengganti nama panel dapat mengubah tujuan user setelah login.isAccessibleTo()berjalan pada setiap request ke panel dan sekali lagi untuk home redirect. JagacanAccess()tetap ringan; satu query per request per user berarti satu query tambahan pada setiap page view.
Lihat juga
- Redirect guest, home redirect
- Registrasi middleware, perilaku service provider, registrasi route
- Integrasi Fortify, login panel, registration, password reset, verifikasi email
- Two-factor, email code challenge
- Aturan akses panel, middleware dan guard, id, path, dan domain
- Siklus request, routing
- Response 403, route panel yang 404
- Masalah instalasi umum, setup Laravel Vue starter kit