You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

69 lines
2.7 KiB

import jwt
from fastapi import Request, HTTPException
from fastapi.responses import JSONResponse
from config import settings
from database import AsyncSessionLocal
from models import User, UserRole, Role, RolePermission, Permission
from sqlalchemy import select
async def rbac_middleware(request: Request, call_next):
public_paths = ["/api/auth/login", "/api/auth/wecom", "/health", "/docs", "/openapi.json", "/wecom/callback"]
if any(request.url.path.startswith(p) for p in public_paths):
return await call_next(request)
token = request.headers.get("Authorization", "").replace("Bearer ", "")
if not token:
return JSONResponse({"code": 401, "message": "未提供认证令牌"}, 401)
try:
payload = jwt.decode(token, settings.JWT_SECRET, algorithms=[settings.JWT_ALGORITHM])
user_id = payload.get("sub")
except jwt.PyJWTError:
return JSONResponse({"code": 401, "message": "令牌无效或已过期"}, 401)
async with AsyncSessionLocal() as db:
result = await db.execute(select(User).where(User.id == user_id))
user = result.scalar_one_or_none()
if not user or user.status != "active":
return JSONResponse({"code": 401, "message": "用户不存在或已禁用"}, 401)
ur_result = await db.execute(
select(Role).join(UserRole).where(UserRole.user_id == user.id)
)
roles = ur_result.scalars().all()
role_codes = [r.code for r in roles]
is_root = "root" in role_codes
permissions = []
data_scopes = []
for role in roles:
data_scopes.append(role.data_scope)
rp_result = await db.execute(
select(Permission).join(RolePermission).where(RolePermission.role_id == role.id)
)
perms = rp_result.scalars().all()
permissions.extend([p.code for p in perms])
unique_perms = list(set(permissions))
if is_root and "*:*" not in unique_perms:
unique_perms.insert(0, "*:*")
request.state.user = {
"id": str(user.id),
"username": user.username,
"display_name": user.display_name,
"department_id": str(user.department_id) if user.department_id else None,
"roles": [{"code": r.code, "name": r.name, "data_scope": r.data_scope} for r in roles],
"permissions": unique_perms,
"is_root": is_root,
"data_scope": "all" if is_root or "all" in data_scopes else (
"department" if "department" in data_scopes else
"subordinate_only" if "subordinate_only" in data_scopes else
"self_only"
),
}
return await call_next(request)