Membuat User Pertama
Instalasi baru sudah memiliki Panel, route, dan Login Page — tetapi belum memiliki user. Biasanya langkah pertama yang dilakukan developer adalah membuka tinker, lalu menulis create() dari ingatan sambil menebak column apa saja yang dimiliki User Model aplikasi. panel:user menutup celah tersebut: command membuat account melalui model milik auth guard aplikasi, lalu memberi tahu apakah account itu benar-benar dapat memasuki Panel.
php artisan panel:user Name:
> Ada Lovelace
Email address:
> ada@example.com
Password:
> ********
INFO Created Ada Lovelace <ada@example.com>.
INFO They can sign into the Administrator panel at admin.2
3
4
5
6
7
8
9
10
11
12
Signature
panel:user
{--name= : The account name}
{--email= : The email address to sign in with}
{--password= : The password, prompted for when omitted}
{--guard= : The auth guard whose user model to create, defaults to the application default}
{--panel= : Report whether the new account can reach this panel}2
3
4
5
6
| Option | Default | Catatan |
|---|---|---|
--name= | prompt | required, string, max:255. |
--email= | prompt | required, string, email, max:255. Uniqueness mengikuti constraint database Anda, bukan validation rule command ini. |
--password= | prompt, hidden | required, string, min:8. |
--guard= | config('auth.defaults.guard') | Guard yang provider-nya menentukan model yang akan dibuat. |
--panel= | Panel pertama yang terdaftar | Panel yang digunakan untuk mengecek access. Hanya dilaporkan, tidak menjadi enforcement saat create. |
php artisan panel:user --name=Ada --email=ada@example.com --password=correct-horse
php artisan panel:user --guard=admin --panel=admin
php artisan panel:user --name=Ada --email=ada@example.com --password="$ADMIN_PASSWORD" --no-interaction2
3
Exit code adalah 0 jika sukses dan 1 jika guard, model, atau validation menolak proses.
Model yang Dibuat
Command sengaja tidak meng-hard-code App\Models\User. Model ditentukan dengan menelusuri konfigurasi auth:
--guard= or auth.defaults.guard
↓
auth.guards.{guard}.provider
↓
auth.providers.{provider}.model2
3
4
5
Project yang memiliki App\Models\Admin di balik guard kedua akan mendapatkan model Admin tersebut. Project yang mengganti default User Model juga akan menggunakan model barunya. Menebak App\Models\User memang bekerja pada sebagian besar project, tetapi pada project yang menggunakan model berbeda justru dapat gagal secara diam-diam dengan membuat row pada table yang salah — tepat pada project yang paling membutuhkan command ini.
Dua failure utama berikut sama-sama dilaporkan dan menghasilkan exit code 1:
| Pesan | Penyebab |
|---|---|
No auth guard named [x]. | auth.guards.x.provider bukan string, biasanya karena guard tidak ada. |
The [users] user provider names no model this command can create. | Provider tidak memiliki key model, atau menunjuk ke class yang tidak ada. Provider token atau LDAP dapat menghasilkan kondisi seperti ini. |
Data yang Ditulis
$user->forceFill([
'name' => $attributes['name'],
'email' => $attributes['email'],
'password' => Hash::make($attributes['password']),
'email_verified_at' => now(),
])->save();2
3
4
5
6
forceFill() digunakan, bukan create(), karena command tidak mengetahui $fillable dari model aplikasi. email_verified_at langsung diisi karena user yang dibuat melalui console secara definisi sudah diverifikasi oleh operator yang memiliki akses database. Jika dibiarkan null, user dapat langsung masuk ke verify-email wall pada Panel yang menggunakan ->auth() dengan middleware verified.
Exception apa pun yang terjadi saat save — misalnya unique constraint pada email, atau column NOT NULL yang tidak memiliki default — ditangkap dan dilaporkan sebagai The user could not be created: … lengkap dengan pesan dari database driver.
Access Report
Setelah account berhasil dibuat, command menanyakan kepada Panel apakah account tersebut dapat masuk:
$panel->isAccessibleTo($user);Jawabannya merupakan kombinasi dua pertanyaan independen, dan keduanya harus sama-sama mengizinkan:
// A rule about the panel, in its provider:
->canAccess(static fn (?Authenticatable $user): bool => $user?->is_admin === true)
// A rule about the account, on the model:
final class User extends Authenticatable implements PandaPanel\Contracts\PanelUser
{
public function canAccessPanel(PandaPanel\Core\Panel $panel): bool
{
return $this->hasVerifiedEmail();
}
}2
3
4
5
6
7
8
9
10
11
Karena dua rule tersebut berada di tempat berbeda, command menyebutkan rule mana yang menjawab tidak:
WARN They cannot reach the Administrator panel yet — the panel's own canAccess() says no.
Set whatever that rule reads before signing in.2
WARN They cannot reach the Administrator panel yet — your user model's canAccessPanel() says no.
Set whatever that rule reads before signing in.2
Command hanya melaporkan dan tidak membatalkan creation. User yang masih perlu diberi is_admin adalah state sementara yang valid, bukan error yang harus menghentikan pembuatan account. Selain itu, flag privilege biasanya memang tidak dibuat mass-assignable; bagian berikut menjelaskan alasannya.
Tanpa --panel, Panel yang diperiksa adalah Panel pertama yang diregistrasikan, yang juga menjadi tujuan default ketika user sign-in tanpa konteks Panel tertentu. Dengan --panel=, command menggunakan Panel dengan ID tersebut — lowercase sesuai hasil derivasi nama provider (AdminPanelProvider → admin).
Memberikan Access
Privilege flag yang mass-assignable memungkinkan siapa pun memberikan privilege kepada dirinya sendiri dengan menambahkan field ke form POST. Karena itu example User Model tidak memasukkan is_admin ke $fillable. Promosi account dilakukan sebagai write yang eksplisit:
php artisan tinkeruse App\Models\User;
User::query()->where('email', 'ada@example.com')->first()->forceFill(['is_admin' => true])->save();2
3
Kemudian pastikan Panel menyetujui access tersebut:
use PandaPanel\Core\PanelManager;
app(PanelManager::class)->get('admin')->isAccessibleTo($user); // true2
3
Menjalankan secara Non-Interactive
Semua prompt dilewati ketika input bukan interactive terminal. Prompt yang ditulis ke pipe yang tidak pernah dapat menjawab lebih buruk daripada langsung gagal. Missing value menjadi empty string, lalu validation menjelaskan option mana yang lupa diberikan script:
ERROR The name field is required.
ERROR The email field is required.
ERROR The password field is required.2
3
Artinya CI atau provisioning script harus memberikan ketiga value berikut:
php artisan panel:user \
--name="$ADMIN_NAME" \
--email="$ADMIN_EMAIL" \
--password="$ADMIN_PASSWORD" \
--no-interaction2
3
4
5
panel:install dapat menawarkan menjalankan command ini secara otomatis, tetapi hanya pada interactive terminal. Installer meneruskan --panel={panel} untuk Panel yang baru saja dibuat.
Catatan
- Password rule command ini bukan password policy aplikasi. Command menggunakan
min:8, bukanPassword::defaults(). Ini merupakan console command yang dijalankan operator pemilik database; public sign-up policy yang menolak password pilihan operator sendiri hanya menambah friction tanpa menambah boundary security. Registration form aplikasi tidak terpengaruh. --password=pada command line masuk ke shell history dan dapat terlihat di process list selama command berjalan. Pada shared machine, lebih aman menggunakan hidden prompt atau environment variable.- Typo pada
--paneltidak menghasilkan error. Unknown Panel ID berarti access report tidak ditampilkan, bukan command gagal. Jadi--panel=admnterlihat seperti pembuatan account sukses tetapi tanpa baris access. Jika report yang diharapkan hilang, periksa ID melaluiphp artisan route:list --name=panel.. - Jika tidak ada Panel yang terdaftar, access report juga tidak ada. Account tetap dibuat.
- Command hanya create, bukan update. Menjalankannya dua kali dengan email yang sama akan mengenai unique constraint aplikasi dan menampilkan pesan dari database driver.
Lihat Juga
- Opening your first panel — proses sign-in dan screen tujuan
- Running panel:install — langkah installer yang menawarkan command ini
- CLI: panel:user
- Authentication: the user model, the PanelUser contract
- Panels: access — detail lengkap
canAccess() - Concepts: authorization — policy dan alasan Resource baru menghasilkan 403
- Troubleshooting: 403 from a panel