RABC fejlesztése és beélesítése hibák kijavításával
This commit is contained in:
@@ -10,8 +10,10 @@ from sqlalchemy.orm import selectinload, joinedload
|
||||
from app.db.session import get_db
|
||||
from app.core.security import decode_token, DEFAULT_RANK_MAP
|
||||
from app.models.identity import User, UserRole # JAVÍTVA: Új Identity modell használata
|
||||
from app.models.marketplace.organization import OrgRole, OrganizationMember
|
||||
from app.core.config import settings
|
||||
from app.core.translation_helper import t # Translation helper
|
||||
from app.core.capabilities import SYSTEM_CAPABILITIES_MATRIX, role_has_capability
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@@ -104,13 +106,13 @@ async def get_current_active_user(
|
||||
return current_user
|
||||
|
||||
async def check_resource_access(
|
||||
resource_scope_id: Union[str, int],
|
||||
resource_scope_id: Union[str, int],
|
||||
current_user: User = Depends(get_current_user)
|
||||
):
|
||||
"""
|
||||
Scoped RBAC: Megakadályozza a jogosulatlan hozzáférést mások adataihoz.
|
||||
"""
|
||||
if current_user.role == UserRole.superadmin:
|
||||
if current_user.role == UserRole.SUPERADMIN:
|
||||
return True
|
||||
|
||||
user_scope = str(current_user.scope_id) if current_user.scope_id else None
|
||||
@@ -161,17 +163,138 @@ async def get_current_admin(
|
||||
"""
|
||||
Csak admin/moderátor/superadmin szerepkörrel rendelkező felhasználók számára.
|
||||
"""
|
||||
# A UserRole Enum értékeit használjuk
|
||||
# A UserRole Enum értékeit használjuk (RBAC Phase 1)
|
||||
allowed_roles = {
|
||||
UserRole.superadmin,
|
||||
UserRole.admin,
|
||||
UserRole.region_admin,
|
||||
UserRole.country_admin,
|
||||
UserRole.moderator,
|
||||
UserRole.SUPERADMIN,
|
||||
UserRole.ADMIN,
|
||||
UserRole.MODERATOR,
|
||||
}
|
||||
if current_user.role not in allowed_roles:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_403_FORBIDDEN,
|
||||
detail=t("AUTH.INSUFFICIENT_ADMIN_PERMISSIONS")
|
||||
)
|
||||
return current_user
|
||||
return current_user
|
||||
|
||||
|
||||
# ═══════════════════════════════════════════════════════════════════════════════
|
||||
# RBAC Phase 2: Capability Dependencies (Kapuőrök)
|
||||
# ═══════════════════════════════════════════════════════════════════════════════
|
||||
|
||||
def RequireSystemCapability(capability_name: str):
|
||||
"""
|
||||
🎯 Rendszerszintű képesség-ellenőrző dependency.
|
||||
|
||||
Használat:
|
||||
@router.get("/admin/users")
|
||||
async def list_users(
|
||||
db: AsyncSession = Depends(get_db),
|
||||
current_user: User = Depends(get_current_user),
|
||||
_ = Depends(RequireSystemCapability("can_manage_users"))
|
||||
):
|
||||
|
||||
Logika:
|
||||
1. Ha a user SUPERADMIN → azonnal átengedi (True).
|
||||
2. Egyébként lekéri a user role-ját, és ellenőrzi a
|
||||
SYSTEM_CAPABILITIES_MATRIX-ból, hogy a kért capability True-e.
|
||||
3. Ha nincs meg a capability → 403 Forbidden.
|
||||
"""
|
||||
async def system_capability_checker(
|
||||
current_user: User = Depends(get_current_user),
|
||||
) -> bool:
|
||||
# SUPERADMIN mindent visz
|
||||
if current_user.role == UserRole.SUPERADMIN:
|
||||
return True
|
||||
|
||||
# Ellenőrizzük a SYSTEM_CAPABILITIES_MATRIX-ból
|
||||
role_key = current_user.role.value # pl. "ADMIN", "MODERATOR", "USER"
|
||||
if not role_has_capability(role_key, capability_name):
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_403_FORBIDDEN,
|
||||
detail=f"SYSTEM_CAPABILITY_DENIED: A '{capability_name}' képesség nem elérhető a '{role_key}' szerepkör számára."
|
||||
)
|
||||
return True
|
||||
|
||||
return system_capability_checker
|
||||
|
||||
|
||||
def RequireOrgCapability(capability_name: str):
|
||||
"""
|
||||
🎯 Szervezeti képesség-ellenőrző dependency.
|
||||
|
||||
Használat:
|
||||
@router.post("/expenses")
|
||||
async def create_expense(
|
||||
expense: AssetCostCreate,
|
||||
db: AsyncSession = Depends(get_db),
|
||||
current_user: User = Depends(get_current_user),
|
||||
_ = Depends(RequireOrgCapability("can_add_expense"))
|
||||
):
|
||||
|
||||
Logika:
|
||||
1. Ha a user SUPERADMIN → azonnal átengedi (True).
|
||||
2. Lekéri a user OrgRole-ját az adott organization_id alapján
|
||||
a fleet.organization_members táblából.
|
||||
3. Kikeresi a fleet.org_roles táblából a szerepkörhöz tartozó
|
||||
permissions JSONB oszlopot.
|
||||
4. Ha a JSONB-ben a kért capability_name nem True → 403 Forbidden.
|
||||
|
||||
Fontos: Ez a dependency egy organization_id paramétert vár a végponttól.
|
||||
A végpontnak át kell adnia az org_id-t a dependency-nek.
|
||||
"""
|
||||
async def org_capability_checker(
|
||||
organization_id: int,
|
||||
db: AsyncSession = Depends(get_db),
|
||||
current_user: User = Depends(get_current_user),
|
||||
) -> bool:
|
||||
# SUPERADMIN mindent visz
|
||||
if current_user.role == UserRole.SUPERADMIN:
|
||||
return True
|
||||
|
||||
# 1. Lekérjük a user szerepkörét a szervezetben
|
||||
member_stmt = select(OrganizationMember.role).where(
|
||||
OrganizationMember.user_id == current_user.id,
|
||||
OrganizationMember.organization_id == organization_id,
|
||||
OrganizationMember.status == "active"
|
||||
).limit(1)
|
||||
member_result = await db.execute(member_stmt)
|
||||
org_role_name = member_result.scalar_one_or_none()
|
||||
|
||||
if not org_role_name:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_403_FORBIDDEN,
|
||||
detail="ORG_MEMBERSHIP_REQUIRED: You are not a member of this organization."
|
||||
)
|
||||
|
||||
# 2. Lekérjük a szerepkör permissions JSONB-jét a fleet.org_roles táblából
|
||||
role_stmt = select(OrgRole.permissions).where(
|
||||
OrgRole.name_key == org_role_name,
|
||||
OrgRole.is_active == True
|
||||
).limit(1)
|
||||
role_result = await db.execute(role_stmt)
|
||||
permissions = role_result.scalar_one_or_none()
|
||||
|
||||
if not permissions:
|
||||
# Fallback: ha nincs a fleet.org_roles táblában, használjuk a
|
||||
# OrganizationMember.permissions mezőt (örökölt viselkedés)
|
||||
member_perm_stmt = select(OrganizationMember.permissions).where(
|
||||
OrganizationMember.user_id == current_user.id,
|
||||
OrganizationMember.organization_id == organization_id,
|
||||
OrganizationMember.status == "active"
|
||||
).limit(1)
|
||||
member_perm_result = await db.execute(member_perm_stmt)
|
||||
permissions = member_perm_result.scalar_one_or_none() or {}
|
||||
|
||||
# 3. Ellenőrizzük a kért képességet
|
||||
if not isinstance(permissions, dict):
|
||||
permissions = {}
|
||||
|
||||
if not permissions.get(capability_name, False):
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_403_FORBIDDEN,
|
||||
detail=f"ORG_CAPABILITY_DENIED: A '{capability_name}' képesség nem elérhető a '{org_role_name}' szerepkör számára ebben a szervezetben."
|
||||
)
|
||||
|
||||
return True
|
||||
|
||||
return org_capability_checker
|
||||
Reference in New Issue
Block a user