Login
Login Page merupakan pintu masuk milik Panel sendiri.
Page tersedia pada path Panel, menggunakan branding Panel, tetapi mengirim login form ke endpoint milik Fortify.
Gunakan fitur ini jika user Panel seharusnya tidak diarahkan melalui generic application Login Page.
Contoh:
Customer Portal
dan
Staff Back Office2
3
dapat memiliki branding sangat berbeda tetapi tetap menggunakan authentication backend yang sama.
Contoh Minimal
<?php
declare(strict_types=1);
namespace App\Panels\Admin;
use PandaPanel\Core\Panel;
use PandaPanel\Core\PanelProvider;
final class AdminPanelProvider
extends PanelProvider
{
public function panel(
Panel $panel
): Panel {
return $panel
->path('admin')
->brandName(
'Acme Operations'
)
->icon('shield')
->auth()
->login();
}
}2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
Cek redirect:
curl -sI https://example.test/admin | grep LocationLocation: https://example.test/admin/loginGuest yang membuka Panel URL:
/admin/...akan diarahkan ke:
/admin/loginIntended URL tetap disimpan, sehingga setelah login user kembali ke tujuan awal.
API
public function login(
bool $login = true
): self;
public function hasLogin():
bool;2
3
4
5
6
login() melakukan tiga hal:
- mendaftarkan
GET {panel}/login; - menjadi gate bagi Registration, Password Reset, dan Email Verification;
- mengubah guest redirect melalui
PanelLoginRedirect.
Route:
panel.{id}.auth.loginComponent:
panel/auth/LoginContoh:
use PandaPanel\Core\PanelManager;
$panel =
app(PanelManager::class)
->get('admin');
$panel->hasLogin();
// true
$panel->routeName(
'auth.login'
);
// panel.admin.auth.login
route(
$panel->routeName(
'auth.login'
)
);
// https://example.test/admin/login2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
Middleware Login Page
Login route diregistrasikan di luar authenticated Panel route group.
Stack:
[
...$panel
->getBaseMiddleware(),
PandaPanel\Http\Middleware\ResolvePanel::class
. ':'
. $panel->getId(),
]2
3
4
5
6
7
8
Default base middleware:
webSession, CSRF, dan Inertia middleware tetap harus tersedia.
auth tidak boleh digunakan karena user yang belum authenticated harus dapat membuka Login Page.
Props
PanelAuthController::login():
public function login(
Request $request
): Response {
return Inertia::render(
'panel/auth/Login',
[
'panel' =>
$this
->panel()
->toSharedArray(),
'canResetPassword' =>
Features::enabled(
Features::resetPasswords()
)
&& $this
->panel()
->hasPasswordReset(),
'canRegister' =>
Features::enabled(
Features::registration()
)
&& $this
->panel()
->hasRegistration(),
'status' =>
$request
->session()
->get('status'),
]
);
}2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
| Prop | Type | Sumber |
|---|---|---|
panel | PanelDefinition | Panel::toSharedArray() |
canResetPassword | bool | Fortify reset feature AND Panel passwordReset |
canRegister | bool | Fortify registration feature AND Panel registration |
status | string|null | Fortify flash status |
Link Registration atau Password Reset hanya ditampilkan jika Fortify dan Panel sama-sama mengaktifkannya.
Submit Login
Login.vue menggunakan Wayfinder:
<script setup lang="ts">
import { Form } from '@inertiajs/vue3';
import { store } from '@/routes/login';
</script>
<template>
<Form
v-bind="store.form()"
:reset-on-success="[
'password',
]"
>
<!-- email, password, remember -->
</Form>
</template>2
3
4
5
6
7
8
9
10
11
12
13
14
15
store adalah:
POST /loginroute:
login.storemilik Fortify.
Jadi seluruh:
- rate limiting;
- session regeneration;
- remember-me;
- TOTP challenge;
- Passkey flow;
tetap berada di satu authentication backend.
Login Page juga menampilkan:
PasskeyVerify.vueyang menggunakan:
@laravel/passkeys/vueJika browser tidak mendukung WebAuthn, component tersebut menyembunyikan dirinya sepenuhnya.
Branding
PanelAuthLayout.vue hanya menampilkan elemen yang relevan bagi guest:
- Panel icon;
- brand name;
- auth form.
Tidak ada:
- sidebar;
- navigation;
- notification bell;
- user menu.
Brand berasal dari:
$panel
->brandName(
'Acme Operations'
)
->icon(
'shield'
)
->colors([
// ...
]);2
3
4
5
6
7
8
9
10
Brand link serta link:
Forgot password
Sign up2
dibangun menggunakan:
panel.pathsehingga otomatis mengikuti perubahan path Panel.
Guest Redirect
Rule:
PandaPanel\Support\PanelLoginRedirectAPI:
public static function for(
Illuminate\Http\Request $request
): ?string;2
3
Behavior:
| Situasi | Redirect |
|---|---|
| Request menuju Panel dengan Login Page | Login Page milik Panel |
| Panel tidak memiliki Login Page | route('login') atau null |
| Request bukan Panel | Application route('login') atau null |
| Panel menyatakan punya Login tetapi route tidak tersedia | null; application Login tidak digunakan sebagai fallback |
Registration dilakukan ke Laravel authentication redirect hooks setelah Kernel di-resolve.
Jika ingin mempertahankan custom redirect sendiri:
// config/panda-panel.php
'register_guest_redirect' =>
false,2
3
4
Kemudian:
// bootstrap/app.php
use Illuminate\Foundation\Configuration\Middleware;
use PandaPanel\Support\PanelLoginRedirect;
->withMiddleware(
function (
Middleware $middleware
): void {
$middleware
->redirectGuestsTo(
fn ($request) =>
PanelLoginRedirect::for(
$request
)
?? route(
'welcome'
)
);
}
)2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
Redirect Setelah Login
Fortify Login Response:
redirect()->intended(...)Contoh:
user membuka
/admin/users/3/edit
↓
guest redirect
/admin/login
↓
login berhasil
↓
kembali
/admin/users/3/edit2
3
4
5
6
7
8
9
10
Jika Login Page dibuka langsung, tidak ada intended URL.
Fallback biasanya ke:
/dashboardRedirectPanelHome dapat mengalihkan user ke first accessible Panel.
Config:
'home_redirect' => [
'enabled' =>
true,
'paths' => [
'dashboard',
],
],2
3
4
5
6
7
8
Testing
use Inertia\Testing\AssertableInertia;
it(
'serves the panel own login page to a guest',
function (): void {
$this
->get('/admin/login')
->assertOk()
->assertInertia(
fn (
AssertableInertia $page
) =>
$page
->component(
'panel/auth/Login'
)
->where(
'panel.name',
'Administrator'
)
->where(
'canResetPassword',
true
)
);
}
);2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
Redirect:
$this
->get('/admin')
->assertRedirect(
'/admin/login'
);
expect(
session(
'url.intended'
)
)->toContain(
'/admin'
);2
3
4
5
6
7
8
9
10
11
12
13
Hal yang Perlu Diperhatikan
canAccess()juga dijalankan pada Login Page.- Guest bernilai
null, sehingga Panel access callback harus memperbolehkan guest jika Login Page ingin dapat dibuka.
Contoh:
->canAccess(
static fn (
?Authenticatable $user
): bool =>
$user === null
|| $user->is_admin === true
)2
3
4
5
6
7
Authenticated Panel Pages tetap aman karena auth berjalan sebelum ResolvePanel.
login()tanpaauth()menghasilkan pintu pada Panel yang tidak protected.- Logout tetap milik application.
- Signed-in user masih dapat membuka
/panel/login, karena Login Page tidak memakaiguestmiddleware. - Beberapa Panel dapat memiliki Login Page berbeda tetapi session authentication tetap satu.