Dalam tahap awal pengembangan aplikasi web, perancangan model otorisasi pengguna biasanya tampak sangat sederhana. Tim pengembang cukup menambahkan kolom role berformat enum (admin, manager, editor, viewer) pada tabel pengguna di database. Namun, seiring dengan pertumbuhan skala bisnis korporat, kebutuhan izin akses berkembang jauh melampaui label peran statis tersebut.
Departemen kepatuhan dan audit internal akan mulai mengajukan aturan bisnis yang kompleks:
- "Manajer Cabang Surabaya hanya boleh menyetujui transaksi kredit hingga nominal 500 juta rupiah, dan persetujuan tersebut hanya sah jika dilakukan pada jam kerja (08.00 - 17.00 WIB) dari jaringan VPN internal kantor."
- "Auditor eksternal boleh melihat dokumen laporan keuangan, namun kolom nomor rekening bank dan identitas nasabah harus disamarkan (masked)."
Jika arsitek sistem bersikukuh menggunakan pola Role-Based Access Control (RBAC) murni untuk mengakomodasi aturan-aturan di atas, sistem akan terjerumus ke dalam fenomena yang dikenal sebagai Role Explosion. Database akan dipenuhi puluhan bahkan ratusan kombinasi peran buatan, seperti Manager_Surabaya_Limit500Jt_VPN_Only, yang membuat pemeliharaan izin akses menjadi mimpi buruk operasional.
Solusi arsitektur yang mampu memecahkan masalah ini secara elegan adalah transisi menuju Attribute-Based Access Control (ABAC) atau model hibrida modern.
Perbandingan Alur Evaluasi Izin Akses RBAC vs ABAC:
Model RBAC Klasik (Statis):
[Pengguna] ────> [Peran: Manager] ────> [Izin: Approve_Loan] ────> Akses Diberikan
Model ABAC Modern (Dinamis Berbasis Atribut):
[Konteks Permintaan]
├── Subjek (User) : Peran=Manager, Cabang=Surabaya, Clearance=Lvl2
├── Tindakan (Action) : Approve_Loan
├── Sumber Daya (Res) : Pinjaman, Nilai=Rp 450 Juta, Wilayah=Surabaya
└── Lingkungan (Env) : Waktu=14:30 WIB, IP=10.15.0.44 (Internal VPN)
│
▼
[Policy Decision Point (PDP)] ────> Mengevaluasi Matriks Kebijakan
│
▼
Hasil: IZIN DIBERIKAN (Memenuhi seluruh kriteria atribut)
Membedah Empat Pilar Komponen ABAC #
Berbeda dengan RBAC yang hanya memeriksa kecocokan string peran, ABAC mengevaluasi hak akses menggunakan empat kategori atribut secara dinamis pada saat permintaan berlangsung (runtime evaluation):
- Atribut Subjek (Subject Attributes): Informasi mengenai identitas pengguna yang melakukan request, meliputi ID karyawan, divisi departemen, level senioritas, lokasi cabang penugasan, dan status validasi otentikasi dua faktor (MFA).
- Atribut Tindakan (Action Attributes): Operasi yang hendak dieksekusi terhadap sistem, seperti
read,create,update,approve,export_csv, ataudelete. - Atribut Sumber Daya (Resource Attributes): Karakteristik dari objek data yang menjadi target tindakan, seperti status dokumen (
draft,pending_approval,archived), pemilik dokumen, klasifikasi kerahasiaan (confidential, restricted), dan batas plafon nilai moneter. - Atribut Lingkungan (Environment / Context Attributes): Kondisi kontekstual eksternal saat transaksi terjadi, seperti waktu hari (time of day), hari kerja kalender, alamat IP pengirim, deteksi lokasi geografis, dan postur keamanan perangkat (device compliance score).
Implementasi ABAC Menggunakan CASL pada Ekosistem TypeScript / Node.js #
Untuk menghindari penulisan puluhan percabangan if-else yang berserak di dalam controller aplikasi, kita dapat memanfaatkan engine evaluasi kebijakan deklaratif seperti CASL (@casl/ability).
Berikut adalah implementasi pabrik izin (ability factory) berbasis ABAC:
// auth/ability.factory.ts
import { AbilityBuilder, createMongoAbility, MongoAbility } from '@casl/ability';
export interface UserSubject {
id: string;
department: string;
branch: string;
approvalLimit: number;
roles: string[];
}
export interface LoanTransaction {
id: string;
amount: number;
branch: string;
status: 'DRAFT' | 'PENDING' | 'APPROVED';
department: string;
}
export interface SecurityContext {
currentTime: Date;
isVpnConnected: boolean;
clientIp: string;
}
export type AppAbility = MongoAbility<[string, any]>;
export function defineAbilityFor(
user: UserSubject,
context: SecurityContext
): AppAbility {
const { can, cannot, build } = new AbilityBuilder<AppAbility>(createMongoAbility);
// Aturan 1: Semua staf dapat membaca transaksi di departemen mereka sendiri
can('read', 'LoanTransaction', { department: user.department });
// Aturan 2: Role Manager dapat menyetujui transaksi pinjaman DENGAN SYARAT:
// - Nilai pinjaman tidak melebihi batas limit approval user
// - Cabang pinjaman sesuai dengan cabang penugasan user
// - Status pinjaman masih PENDING
if (user.roles.includes('FINANCE_MANAGER')) {
can('approve', 'LoanTransaction', {
branch: user.branch,
amount: { $lte: user.approvalLimit },
status: 'PENDING',
});
}
// Aturan 3 (Konteks Lingkungan ABAC):
// Menolak seluruh tindakan persetujuan jika di luar jam kerja (08.00 - 17.00 WIB)
const currentHour = context.currentTime.getHours();
const isWorkingHours = currentHour >= 8 && currentHour < 17;
if (!isWorkingHours || !context.isVpnConnected) {
cannot('approve', 'LoanTransaction').because(
'Persetujuan transaksi finansial hanya diizinkan pada jam kerja resmi melalui jaringan VPN internal.'
);
}
return build();
}
Penggunaan di dalam service transaksi perbankan:
// services/loan.service.ts
import { ForbiddenError } from '@casl/ability';
import { defineAbilityFor, UserSubject, SecurityContext, LoanTransaction } from '../auth/ability.factory';
export class LoanService {
async approveLoan(
currentUser: UserSubject,
loanData: LoanTransaction,
context: SecurityContext
) {
const ability = defineAbilityFor(currentUser, context);
// Evaluasi aturan ABAC secara atomik
ForbiddenError.from(ability).throwUnlessCan('approve', loanData);
// Lanjutkan mutasi database jika evaluasi kebijakan lolos
return await this.executeApproval(loanData.id, currentUser.id);
}
private async executeApproval(loanId: string, approverId: string) {
// Eksekusi mutasi status database ke APPROVED
return { status: 'SUCCESS', loanId, approvedBy: approverId };
}
}
Logging Kepatuhan dan Audit Trail Regulasi #
Penerapan otorisasi tingkat enterprise tidak lengkap tanpa sistem pencatatan jejak audit (audit trail) yang tidak dapat dimanipulasi (immutable). Standar regulasi keamanan data seperti ISO 27001 klausul 9.4 dan Undang-Undang Pelindungan Data Pribadi (UU PDP) mewajibkan setiap penolakan izin akses penting terekam lengkap beserta konteks atributnya.
Setiap evaluasi kebijakan yang gagal wajib menghasilkan log terstruktur:
{
"timestamp": "2026-11-09T14:45:10.120Z",
"event_type": "ACCESS_DENIED",
"actor": {
"user_id": "usr_94819",
"roles": ["FINANCE_MANAGER"],
"branch": "Surabaya"
},
"action": "approve",
"resource": {
"type": "LoanTransaction",
"id": "loan_7741",
"amount": 750000000,
"branch": "Surabaya"
},
"context": {
"ip": "180.252.11.4",
"is_vpn": true,
"denial_reason": "amount exceeds user approval limit of 500000000"
}
}
Rekomendasi Pemilihan Arsitektur #
Sebagai panduan strategis bagi arsitek perangkat lunak korporat:
- Mulailah dengan RBAC sederhana jika model bisnis Anda memiliki peran yang seragam tanpa variasi kewenangan berbasis cabang, limit finansial, atau aturan jam kerja.
- Adopsi Model Hibrida (RBAC dengan Kendala ABAC) saat aplikasi mulai melayani multi-tenant atau hierarki cabang regional. Gunakan peran umum sebagai fondasi awal, kemudian terapkan filter atribut granular pada tingkat baris data (row-level security).
- Pisahkan modul evaluasi kebijakan (Policy Decision Point) dari kode controller utama. Pemisahan ini memastikan aturan otorisasi dapat diaudit dan diperbarui oleh tim kepatuhan tanpa harus merombak alur logika bisnis inti aplikasi.
