Lompat ke konten
dokumentasi.id
Commit b472665
v1
Star1,3 rb

4

Autentikasi dan Otorisasi

Semua route dashboard memakai guard sanctum yang ditunjuk kunci konfigurasi badaso.authenticate.guard src/Config/badaso.php:10-12. Token yang beredar bukan token Sanctum polos: TokenManagement membentuk nama token dan dua ability tambahan src/Helpers/TokenManagement.php:14-16, sementara expiration milik Sanctum sendiri bernilai null src/Config/sanctum.php:33. 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-38, src/Helpers/TokenManagement.php:108-127.

AbilityDibentuk olehNilai yang disimpan
remembergetRememberAbility($remember)remember: diikuti nilai boolean yang diinterpolasi
expired_dategetExpiredDateAbility($remember)expired_date: diikuti hasil Carbon::now()->addMinutes(...)
nama tokengetTokenName($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-30. Perhitungannya dilakukan getExpiredDateAbility() src/Helpers/TokenManagement.php:40-51, lalu createToken() menempelkan kedua ability itu ke user->createToken() dan menyimpan plainTextToken src/Helpers/TokenManagement.php:53-65.

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.
Fig. 1: Login sampai token terbitValidasi 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-108. 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-137. Respons sukses yang membawa token berbentuk objek dengan access_token, token_type bernilai Bearer, dan data user src/Helpers/TokenManagement.php:84-92.

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-88.

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.
Fig. 2: Perpindahan status tokenToken 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-76. deleteToken() cukup menghapus currentAccessToken() src/Helpers/TokenManagement.php:78-82, dan itulah yang dipanggil logout() src/Controllers/BadasoAuthController.php:143-156.

⚠️ hasTimeoutConnection() menghapus token yang expired_date-nya sudah lewat, tetapi fungsi ini tidak mengembalikan nilai apa pun src/Helpers/TokenManagement.php:94-106. Karena isAuthorize() hanya mengembalikan false ketika hasil pemanggilan itu truthy src/Middleware/BadasoAuthenticate.php:31-50, 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-29. BadasoAuthController memasang middleware ini pada semua method kecuali secretLogin, login, register, forgetPassword, resetPassword, verify, reRequestVerification, dan validateTokenForgetPassword src/Controllers/BadasoAuthController.php:32-35 — karena itu refreshToken() wajib membawa token src/Controllers/BadasoAuthController.php:246-253. Helper TokenManagement::fromAuth() mengambil user dari guard yang sama agar middleware dan controller memeriksa identitas yang identik src/Helpers/TokenManagement.php:129-139.

Setelah identitas lolos, getAuthenticatedUser() mengembalikan user beserta roles dan permissions hasil AuthenticatedUser::getUser() src/Controllers/BadasoAuthController.php:255-268. getUser() menempelkan roles lewat join user_roles ke roles dan permissions lewat join role_permissions ke permissions src/Helpers/AuthenticatedUser.php:12-21.

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.
Fig. 3: Urutan pemeriksaan permissionMiddleware 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-34. 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-62.

⚠️ AuthenticatedUser::ignore() dipanggil sebelum identitas diperiksa, dan ia meloloskan setiap permission yang is_public atau always_allow bernilai 1 src/Helpers/AuthenticatedUser.php:64-77. Seeder bawaan menetapkan read_crud_data dengan always_allow = 1 src/Seeder/Configurations/PermissionsSeeder.php:22-26, 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-41. Key inilah yang dibuat Permission::generateFor() untuk setiap tabel, yaitu browse_, read_, edit_, add_, delete_, dan maintenance_ src/Models/Permission.php:31-38. Route entities mendaftarkan middleware ini per slug dan per aksi saat aplikasi dijalankan src/Routes/api.php:159-190. 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:35, src/Routes/api.php:26-45.

MethodPathHandlerButuh token
POST/v1/auth/loginlogintidak
POST/v1/auth/registerregistertidak
POST/v1/auth/logoutlogoutya
POST/v1/auth/forgot-passwordforgetPasswordtidak
POST/v1/auth/forgot-password-verifyvalidateTokenForgetPasswordtidak
POST/v1/auth/reset-passwordresetPasswordtidak
POST/v1/auth/refresh-tokenrefreshTokenya
POST/v1/auth/verifyverifytidak
POST/v1/auth/re-request-verificationreRequestVerificationtidak
POST/v1/auth/{VITE_BADASO_SECRET_LOGIN_PREFIX}secretLogintidak
GET/v1/auth/usergetAuthenticatedUserya
PUT/v1/auth/user/change-passwordchangePasswordya
PUT/v1/auth/user/profileupdateProfileya
PUT/v1/auth/user/emailupdateEmailya
POST/v1/auth/user/verify-emailverifyEmailya

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-119. ApiResponse::forbidden() memakai HTTP status 403 dengan pesan dari badaso::api_response.403 src/Helpers/ApiResponse.php:121-128. 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-87.