Neues crm-Paket mit Datenmodell, Geschäftslogik und REST-Endpunkten
für die Entität Kunde (/xhr/kunde/{list,get,create,update,delete}).
authorisation_required-Decorator: app-spezifische Rollenprüfung via
has_permission(appid, ...). SysAdmin systemweit, AppAdmin implizit in
seiner Anwendung, User (Mitarbeiter) als Basis-Rolle, Zusatz-Rollen
wie KundenManager additiv.
Flask CLI: init-db (Schema + Musterdaten + App-Rollen) und reset-db
(Bestätigung, behält SysAdmin).
config.ini: Neuer appid-Eintrag (KBPlusCRM), getrennt vom technischen
PROJEKTNAME. checkdb: appid aus config, Migration _db_V01_02 für
bestehende DBs.
Generated by Mistral Vibe.
Co-Authored-By: Mistral Vibe <vibe@mistral.ai>
98 lines
4.3 KiB
Python
98 lines
4.3 KiB
Python
"""
|
|
Decoratoren zur Authentifizierungs- und Autorisierungsprüfung.
|
|
|
|
Der Decorator authorisation_required hebt die Rollenprüfung an die Route-Ebene,
|
|
analog zu flask_login.login_required. Authentifizierung (login_required) ist
|
|
eingebettet, sodass pro Endpunkt nur ein Decorator nötig ist.
|
|
|
|
:author: Mistral Vibe <vibe@mistral.ai>
|
|
:date: 2026-09-02
|
|
:version: 1.0
|
|
"""
|
|
from functools import wraps
|
|
|
|
from flask import current_app
|
|
from flask_login import current_user, login_required
|
|
|
|
from auth.model import APP_ADMIN
|
|
from auth.model.errors import AutorisationError
|
|
|
|
|
|
def authorisation_required(allowed_roles=[]):
|
|
"""
|
|
Decorator, der sicherstellt, dass der angemeldete Benutzer für den
|
|
Endpunkt autorisiert ist. Authentifizierung (login_required) ist eingebettet,
|
|
sodass kein zusätzlicher @login_required-Aufruf nötig ist.
|
|
|
|
Aspekte der Autorisierung (Prüfreihenfolge):
|
|
|
|
1. SysAdmin (systemweite Super-Rolle):
|
|
Der SysAdmin darf alles, unabhängig von der Anwendung. Er braucht in
|
|
keiner Application eine Rolle zugewiesen zu haben. Die Prüfung erfolgt
|
|
über User.is_SysAdmin() (app-übergreifend). Dies ist die einzige Rolle,
|
|
die applikationsübergreifend gilt — sie ist eine Systemrolle, keine
|
|
App-Rolle.
|
|
|
|
2. AppAdmin (anwendungsbezogene Verwaltungsrolle):
|
|
Der AppAdmin darf innerhalb der Anwendung alles, der er zugeordnet ist.
|
|
Er braucht die Rolle AppAdmin nur in der aktuellen Anwendung. Der
|
|
Decorator ergänzt allowed_roles intern um APP_ADMIN, sodass der AppAdmin
|
|
jeden Endpunkt ohne explizite Nennung in allowed_roles passiert. Die
|
|
Prüfung erfolgt über User.has_permission(appid, [..., APP_ADMIN]) —
|
|
app-spezifisch, nicht systemweit.
|
|
|
|
3. Benutzer mit Basis-Rolle 'User' (Mitarbeiter):
|
|
Jeder Anwender hat zwingend die Basis-Rolle 'User' (Mitarbeiter), damit
|
|
er das Login-Gate in auth/routes.checklogin passiert. Diese Rolle allein
|
|
berechtigt nur zu Lese-Endpunkten, bei denen MITARBEITER in allowed_roles
|
|
steht. Für Schreib-Endpunkte reicht 'User' nicht.
|
|
|
|
4. Benutzer mit Zusatz-Rollen (z.B. KundenManager, später ProjektManager):
|
|
Zusätzlich zur Basis-Rolle 'User' können einem Benutzer weitere Rollen
|
|
zugewiesen werden. Diese gewähren weitergehende Berechtigungen für
|
|
bestimmte Entitäten. Die Prüfung erfolgt app-spezifisch über
|
|
User.has_permission(appid, allowed_roles). Der Benutzer muss die
|
|
Zusatz-Rolle in der aktuellen Anwendung haben, nicht in einer anderen.
|
|
|
|
Die appid der aktuellen Anwendung wird aus app.config["APPID"] gelesen
|
|
(gesetzt in approot.py aus config.ini, Eintrag [APP] appid). Sie ist der
|
|
lesbare Anwendungsname (z.B. 'KBPlusCRM') und dient der Zuordnung in der
|
|
Tabelle 'applications'. Sie ist nicht identisch mit PROJEKTNAME, der nur
|
|
für Datei- und Verzeichnisnamen verwendet wird.
|
|
|
|
- allowed_roles: List[str]
|
|
- roleids (nicht ids) der Rollen, die den Endpunkt zusätzlich zu
|
|
AppAdmin/SysAdmin erlauben. AppAdmin wird intern ergänzt, muss also
|
|
nicht explizit genannt werden. Der Benutzer muss die Rolle in der
|
|
aktuellen Anwendung haben (geprüft via User.has_permission).
|
|
"""
|
|
|
|
def decorator(f):
|
|
@wraps(f)
|
|
@login_required
|
|
def wrapper(*args, **kwargs):
|
|
# appid der aktuellen Anwendung aus der Konfiguration
|
|
appid = current_app.config["APPID"]
|
|
|
|
# 1. SysAdmin darf systemweit alles (keine app-spezifische Prüfung)
|
|
if current_user.is_SysAdmin():
|
|
return f(*args, **kwargs)
|
|
|
|
# 2.-4. AppAdmin und alle anderen Rollen: app-spezifische Prüfung.
|
|
# AppAdmin wird implizit zu allowed_roles hinzugefügt, damit der
|
|
# AppAdmin in seiner Anwendung jeden Endpunkt ohne explizite
|
|
# Nennung in allowed_roles nutzen kann.
|
|
effective_roles = list(allowed_roles) + [APP_ADMIN]
|
|
|
|
if not current_user.has_permission(appid, effective_roles):
|
|
# Rollen des Users in der aktuellen Anwendung für die Fehlermeldung
|
|
user_roles = current_user.get_userapproles(appid)
|
|
raise AutorisationError(
|
|
allowed_roles=allowed_roles, user_roles=user_roles
|
|
)
|
|
return f(*args, **kwargs)
|
|
|
|
return wrapper
|
|
|
|
return decorator
|