Files
zkxw/backend/app/core/mobile_menu_guard.py
T

77 lines
2.3 KiB
Python

"""移动市场接口的严格菜单权限守卫。"""
from typing import Callable, Iterable
from fastapi import Depends, HTTPException
from sqlalchemy.orm import Session
from app.core.auth import get_current_user
from app.core.database import get_db
from app.services.web_auth_roles import (
iter_user_menu_perm_codes,
resolve_web_role_for_user,
)
def require_market_menu_permission(
*,
user_id: str,
tenant_no: str,
required: str,
granted: Iterable[str],
) -> bool:
"""严格判断当前租户用户是否拥有指定移动市场权限码。"""
uid = (user_id or "").strip()
tenant = (tenant_no or "").strip()
code = (required or "").strip()
if not uid or not tenant or not code:
return False
return code in {(item or "").strip() for item in granted if item}
def user_has_tenant_menu_perm(
db: Session,
*,
user_id: str,
tenant_no: str,
perm_code: str,
) -> bool:
"""按显式租户读取用户权限,不回退默认租户。"""
tenant = (tenant_no or "").strip()
uid = (user_id or "").strip()
if not tenant or not uid:
return False
granted = iter_user_menu_perm_codes(db, uid, tenant_no=tenant)
return require_market_menu_permission(
user_id=uid,
tenant_no=tenant,
required=perm_code,
granted=granted,
)
def require_market_menu_code(menu_code: str) -> Callable:
"""为移动市场 API 提供租户化、精确匹配的菜单权限依赖。"""
required = (menu_code or "").strip()
async def dependency(
user: dict = Depends(get_current_user),
db: Session = Depends(get_db),
) -> dict:
tenant_no = str(user.get("tenant_no") or "").strip()
user_id = str(user.get("user_id") or "").strip()
if not tenant_no or not user_id:
raise HTTPException(status_code=403, detail="用户租户或身份信息缺失")
tenant_role = resolve_web_role_for_user(
db, user_id, tenant_no=tenant_no
)
if tenant_role != "super_admin" and not user_has_tenant_menu_perm(
db,
user_id=user_id,
tenant_no=tenant_no,
perm_code=required,
):
raise HTTPException(status_code=403, detail="无移动端菜单权限")
return user
return dependency