4
Autentikasi dan Otorisasi
Semua route dashboard memakai guard sanctum yang ditunjuk kunci konfigurasi badaso.authenticate.guard src/Config/badaso.php:10-121. Token yang beredar bukan token Sanctum polos: TokenManagement membentuk nama token dan dua ability tambahan src/Helpers/TokenManagement.php:14-162, sementara expiration milik Sanctum sendiri bernilai null src/Config/sanctum.php:333. Masa berlaku karena itu dihitung oleh Badaso, bukan oleh Sanctum.
Ability dan masa berlaku token
Setiap token membawa ability remember:{remember} dan expired_date:{tanggal}. Keduanya string yang dipisah titik dua, dan findAbility() membelahnya kembali menjadi key dan value src/Helpers/TokenManagement.php:26-384, src/Helpers/TokenManagement.php:108-1275.
| Ability | Dibentuk oleh | Nilai yang disimpan |
|---|---|---|
remember | getRememberAbility($remember) | remember: diikuti nilai boolean yang diinterpolasi |
expired_date | getExpiredDateAbility($remember) | expired_date: diikuti hasil Carbon::now()->addMinutes(...) |
| nama token | getTokenName($email) | Hash::make("get_token:{$email}"), sehingga nama token berbeda pada setiap login |
Angka masa berlakunya dibaca dari badaso.expired_token: 60 * 24 menit untuk login biasa dan 60 * 24 * 30 menit untuk login dengan remember src/Config/badaso.php:17-306. Perhitungannya dilakukan getExpiredDateAbility() src/Helpers/TokenManagement.php:40-517, lalu createToken() menempelkan kedua ability itu ke user->createToken() dan menyimpan plainTextToken src/Helpers/TokenManagement.php:53-658.
Alur login sampai token tersimpan
sequenceDiagram
autonumber
participant C as Admin Panel
participant A as BadasoAuthController
participant T as TokenManagement
participant U as User
C->>A: POST login email, password, remember
A->>A: validate email dan password lewat Auth::attempt
alt kredensial tidak valid
A-->>C: 400 invalid_credentials
else adminPanelVerifyEmail aktif dan email_verified_at null
A-->>C: 200 ApiResponse::success tanpa token
else kredensial valid
A->>T: fromUser(user) -> createToken(remember)
T->>U: createToken token_name dan abilities
U-->>T: plainTextToken
T-->>A: access_token, token_type, user
A-->>C: 200 ApiResponse::success
end
%% fig: Login sampai token terbit
%% desc: Validasi kredensial, percabangan verifikasi email, dan penerbitan token Bearer oleh TokenManagement.login() memvalidasi email dan password dengan closure yang memanggil Auth::attempt, lalu menggagalkan validasi lewat __('badaso::validation.auth.invalid_credentials') bila kredensial salah src/Controllers/BadasoAuthController.php:98-1089. Bila Config::get('adminPanelVerifyEmail') bernilai '1' dan email_verified_at masih null, method ini tidak menerbitkan token sama sekali; ia membuat UserVerification dan mengembalikan ApiResponse::success() tanpa data src/Controllers/BadasoAuthController.php:111-13710. Respons sukses yang membawa token berbentuk objek dengan access_token, token_type bernilai Bearer, dan data user src/Helpers/TokenManagement.php:84-9211.
secretLogin() menempuh jalur yang sama, termasuk pemeriksaan verifikasi email dan pencatatan activity log dengan nama Authentication, hanya saja dipanggil dari route berprefix rahasia src/Controllers/BadasoAuthController.php:37-8812.
Siklus hidup token
graph LR
CREATE["createToken remember"] --> ACTIVE["PersonalAccessToken aktif"]
ACTIVE -- "refreshToken" --> ROTATE["token lama dihapus lalu createToken lagi"]
ROTATE --> ACTIVE
ACTIVE -- "logout atau deleteToken" --> GONE["token dihapus"]
ACTIVE -- "expired_date sudah lewat" --> STALE["hasTimeoutConnection menghapus token"]
STALE --> GONE
style CREATE fill:#f59e0b,color:#000
style ACTIVE fill:#2d7d46,color:#fff
style ROTATE fill:#8b5cf6,color:#fff
style STALE fill:#dc2626,color:#fff
style GONE fill:#dc2626,color:#fff
%% fig: Perpindahan status token
%% desc: Token dibuat, dirotasi lewat refresh, atau dihapus saat logout dan saat masa berlakunya habis.refreshToken() membaca ability remember dari token yang sedang dipakai, menghapus token lama, lalu menerbitkan token baru dengan nilai remember yang sama src/Helpers/TokenManagement.php:67-7613. deleteToken() cukup menghapus currentAccessToken() src/Helpers/TokenManagement.php:78-8214, dan itulah yang dipanggil logout() src/Controllers/BadasoAuthController.php:143-15615.
⚠️
hasTimeoutConnection()menghapus token yangexpired_date-nya sudah lewat, tetapi fungsi ini tidak mengembalikan nilai apa pun src/Helpers/TokenManagement.php:94-10616. KarenaisAuthorize()hanya mengembalikanfalseketika hasil pemanggilan itu truthy src/Middleware/BadasoAuthenticate.php:31-5017, request yang membawa token kedaluwarsa tetap diteruskan pada permintaan tersebut; token baru benar-benar hilang pada request berikutnya.
Pemeriksaan identitas di middleware
BadasoAuthenticate memperluas Authenticate milik Laravel dan mengganti handle(): bila isAuthorize() benar, request diteruskan ke $next, selain itu ApiResponse::unauthorized() dikembalikan src/Middleware/BadasoAuthenticate.php:22-2918. BadasoAuthController memasang middleware ini pada semua method kecuali secretLogin, login, register, forgetPassword, resetPassword, verify, reRequestVerification, dan validateTokenForgetPassword src/Controllers/BadasoAuthController.php:32-3519 — karena itu refreshToken() wajib membawa token src/Controllers/BadasoAuthController.php:246-25320. Helper TokenManagement::fromAuth() mengambil user dari guard yang sama agar middleware dan controller memeriksa identitas yang identik src/Helpers/TokenManagement.php:129-13921.
Setelah identitas lolos, getAuthenticatedUser() mengembalikan user beserta roles dan permissions hasil AuthenticatedUser::getUser() src/Controllers/BadasoAuthController.php:255-26822. getUser() menempelkan roles lewat join user_roles ke roles dan permissions lewat join role_permissions ke permissions src/Helpers/AuthenticatedUser.php:12-2123.
Pemeriksaan permission
graph TD
R["Route memakai check_permission atau check_crud_permission"] --> M{"middleware permission"}
M -- "nama permission kosong" --> NEXT["next request"]
M --> IGN{"AuthenticatedUser::ignore"}
IGN -- "is_public atau always_allow bernilai 1" --> NEXT
IGN -- "tidak ada yang cocok" --> AUTH{"BadasoAuthenticate::isAuthorize"}
AUTH -- "guard check gagal" --> E401["ApiResponse::unauthorized 401"]
AUTH -- "identitas sah" --> ALLOW{"AuthenticatedUser::isAllowedTo"}
ALLOW -- "irisan permission tidak kosong" --> NEXT
ALLOW -- "irisan kosong" --> E403["ApiResponse::forbidden 403"]
style M fill:#f59e0b,color:#000
style AUTH fill:#f59e0b,color:#000
style IGN fill:#8b5cf6,color:#fff
style ALLOW fill:#8b5cf6,color:#fff
style NEXT fill:#2d7d46,color:#fff
style E401 fill:#dc2626,color:#fff
style E403 fill:#dc2626,color:#fff
%% fig: Urutan pemeriksaan permission
%% desc: Middleware melewati permission publik, memeriksa identitas, lalu mencocokkan key permission milik user sebelum memutuskan 401 atau 403.BadasoCheckPermissions membaca nama permission dari parameter middleware. Bila parameternya null, request langsung diteruskan; bila tidak, AuthenticatedUser::ignore() dicoba lebih dulu, baru setelah itu isAuthorize() dan isAllowedTo() dijalankan src/Middleware/BadasoCheckPermissions.php:11-3424. Daftar permission boleh berisi beberapa key yang dipisah koma, karena isAllowedTo() memecah string dengan explode(',') lalu mencari irisan dengan key milik user src/Helpers/AuthenticatedUser.php:44-6225.
⚠️
AuthenticatedUser::ignore()dipanggil sebelum identitas diperiksa, dan ia meloloskan setiap permission yangis_publicataualways_allowbernilai 1 src/Helpers/AuthenticatedUser.php:64-7726. Seeder bawaan menetapkanread_crud_datadenganalways_allow= 1 src/Seeder/Configurations/PermissionsSeeder.php:22-2627, sehingga route yang hanya memakai permission itu dapat diakses tanpa token. Tinjau nilai tersebut sebelum menambah route baru.
BadasoCheckPermissionsForCRUD memakai dua parameter, yaitu $slug dan $action. Bila DataType dengan slug itu tidak ditemukan, hasilnya langsung ApiResponse::forbidden(); bila generate_permissions bernilai false, request diteruskan tanpa pemeriksaan; selain itu key permission yang dicari berbentuk {action}_{data_type->name} src/Middleware/BadasoCheckPermissionsForCRUD.php:12-4128. Key inilah yang dibuat Permission::generateFor() untuk setiap tabel, yaitu browse_, read_, edit_, add_, delete_, dan maintenance_ src/Models/Permission.php:31-3829. Route entities mendaftarkan middleware ini per slug dan per aksi saat aplikasi dijalankan src/Routes/api.php:159-19030. Rincian pengelolaan role dan permission ada di Manajemen User, Role, dan Permission, dan pembuatan DataType ada di CRUD Generator dan Content Manager.
Endpoint autentikasi
Seluruh route auth berada di bawah prefix v1/auth, dan prefix luarnya diambil dari badaso.api_route_prefix yang default-nya badaso-api src/Config/badaso.php:3531, src/Routes/api.php:26-4532.
| Method | Path | Handler | Butuh token |
|---|---|---|---|
| POST | /v1/auth/login | login | tidak |
| POST | /v1/auth/register | register | tidak |
| POST | /v1/auth/logout | logout | ya |
| POST | /v1/auth/forgot-password | forgetPassword | tidak |
| POST | /v1/auth/forgot-password-verify | validateTokenForgetPassword | tidak |
| POST | /v1/auth/reset-password | resetPassword | tidak |
| POST | /v1/auth/refresh-token | refreshToken | ya |
| POST | /v1/auth/verify | verify | tidak |
| POST | /v1/auth/re-request-verification | reRequestVerification | tidak |
| POST | /v1/auth/{VITE_BADASO_SECRET_LOGIN_PREFIX} | secretLogin | tidak |
| GET | /v1/auth/user | getAuthenticatedUser | ya |
| PUT | /v1/auth/user/change-password | changePassword | ya |
| PUT | /v1/auth/user/profile | updateProfile | ya |
| PUT | /v1/auth/user/email | updateEmail | ya |
| POST | /v1/auth/user/verify-email | verifyEmail | ya |
Bentuk response penolakan
Penolakan identitas dan penolakan permission dibedakan dengan jelas. ApiResponse::unauthorized() mengirim data dan errors bernilai null dengan HTTP status 401 dan pesan dari badaso::api_response.401 src/Helpers/ApiResponse.php:112-11933. ApiResponse::forbidden() memakai HTTP status 403 dengan pesan dari badaso::api_response.403 src/Helpers/ApiResponse.php:121-12834. Keduanya memakai helper send() yang sama seperti response sukses, sehingga bentuk amplop JSON-nya seragam.
Kegagalan kredensial tidak berakhir sebagai 401, melainkan sebagai ValidationException. ApiResponse::failed() memetakan exception itu menjadi HTTP status 400 dengan pesan badaso::api_response.400 beserta daftar errors per field src/Helpers/ApiResponse.php:43-8735.