API — CASL-Permissions
Mehr Hintergrund: Berechtigungen-CASL Konzept.
CASL-Tuple
Jede API-Aktion wird gegen ein CASL-Tuple geprüft:
[action, subject, conditions?]
Beispiele:
["view", "Customer"]— Kunden ansehen["update", "Customer", { "createdBy": "$user.id" }]— nur eigene Kunden ändern["do", "ApproveAbsence"]— Abwesenheit genehmigen
Standard-Actions
| Action | Wann |
|---|---|
view | GET |
create | POST |
update | PATCH/PUT |
delete | DELETE |
do:CustomAction | POST auf Sub-Endpoint |
403-Errors
{
"error": {
"code": "FORBIDDEN",
"message": "Action 'create' on subject 'Customer' not allowed",
"details": {
"missingAbility": [{
"action": "create",
"subject": "Customer"
}],
"userId": "...",
"userRoles": ["Innendienst"]
}
}
}
→ Lösung: Admin gibt User die fehlende Ability via Custom-Rolle.
FE_-Subjects vs. API-Subjects
Pro Modul zwei Subjects:
Customer— Daten-Zugriff (API)FE_Customer— Seiten-Sichtbarkeit (Frontend)
API-Calls prüfen das API-Subject. FE_-Subjects sind nur für UI-Routing.
Conditions (feinere Kontrolle)
{
"action": "view",
"subject": "Workorder",
"conditions": {
"employeeId": "$user.id"
}
}
→ User darf nur Aufträge sehen, bei denen employeeId seine User-ID ist.
Operatoren in Conditions (MongoDB-ähnlich):
$eq,$ne,$gt,$lt,$gte,$lte$in,$nin$or,$and$user.id,$user.tenantId,$user.roleNames
Custom-Actions (do:)
Für Aktionen jenseits CRUD:
| Action | Endpoint | Wofür |
|---|---|---|
do:ApproveAbsence | POST /absences/:id/approve | Urlaub genehmigen |
do:RejectAbsence | POST /absences/:id/reject | Urlaub ablehnen |
do:HandoverSalesDocument | POST /sales-documents/:id/handover | Lifecycle-Übergang |
do:BulkImportAbsences | POST /absences/bulk-import | Bulk-Import |
do:DownloadAccounting | GET /accountings/:id/download | Export |
Token-Abilities Cache
JWT-Token enthält zum Login-Zeitpunkt die Abilities. Bei Rollen-Änderung:
- User muss neu einloggen oder Token-Refresh machen
- Bis dahin gelten die alten Abilities (max. 1h Token-Gültigkeit)
API-Beispiel mit Conditions
GET /api/workorders
Authorization: Bearer <token mit ["view","Workorder",{"employeeId":"$user.id"}]>
# Backend filter automatisch: WHERE employeeId = <user.id>
User sieht nur seine Aufträge — die Condition wird Backend-seitig durchgesetzt.
Hinweis für Frontend-Entwickler
Ability-Check vor API-Call:
import { useAbility } from "@casl/react";
const ability = useAbility(AbilityContext);
if (ability.can("create", "Workorder")) {
// Button zeigen
}
Spart unnötige 403-Errors. Trotzdem: Backend prüft immer unabhängig (defense in depth).
Audit pro 403
Auch fehlgeschlagene Calls werden im Audit-Log mit 403-Status protokolliert. Bei häufigen 403 vom gleichen User: möglicher Privilegien-Eskalations-Versuch.