feat(rbac): add roles and permissions

This commit is contained in:
Schubert Ferenc 2026-07-02 23:05:59 +02:00
parent 86a32a942c
commit 694b7bd09a
37 changed files with 2682 additions and 218 deletions

View file

@ -0,0 +1,94 @@
from collections.abc import Iterable
from fastapi import Depends, HTTPException, status
from fastapi.security import HTTPAuthorizationCredentials, HTTPBearer
from sqlalchemy.orm import Session
from app.core.security import verify_access_token
from app.db.database import get_db
from app.models.user import User
from app.repositories.user_repository import UserRepository
bearer_scheme = HTTPBearer(auto_error=False)
def get_current_user(
credentials: HTTPAuthorizationCredentials | None = Depends(bearer_scheme),
db: Session = Depends(get_db),
) -> User:
if credentials is None:
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Nicht authentifiziert",
headers={"WWW-Authenticate": "Bearer"},
)
username = verify_access_token(credentials.credentials)
user = UserRepository.get_by_username(db, username)
if user is None:
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Nicht authentifiziert",
headers={"WWW-Authenticate": "Bearer"},
)
return user
def get_current_active_user(current_user: User = Depends(get_current_user)) -> User:
if not current_user.is_active:
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Nicht authentifiziert",
headers={"WWW-Authenticate": "Bearer"},
)
return current_user
def get_user_permission_names(user: User) -> set[str]:
if user.primary_role is None:
return set()
return {permission.name for permission in user.primary_role.permissions}
def require_permission(permission: str):
def dependency(current_user: User = Depends(get_current_active_user)) -> User:
if permission not in get_user_permission_names(current_user):
raise HTTPException(
status_code=status.HTTP_403_FORBIDDEN,
detail="Keine Berechtigung",
)
return current_user
return dependency
def require_any_permission(permissions: Iterable[str]):
permission_set = set(permissions)
def dependency(current_user: User = Depends(get_current_active_user)) -> User:
if get_user_permission_names(current_user).isdisjoint(permission_set):
raise HTTPException(
status_code=status.HTTP_403_FORBIDDEN,
detail="Keine Berechtigung",
)
return current_user
return dependency
def require_all_permissions(permissions: Iterable[str]):
permission_set = set(permissions)
def dependency(current_user: User = Depends(get_current_active_user)) -> User:
if not permission_set.issubset(get_user_permission_names(current_user)):
raise HTTPException(
status_code=status.HTTP_403_FORBIDDEN,
detail="Keine Berechtigung",
)
return current_user
return dependency