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.
 
 
 

58 lines
2.3 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", "/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()
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])
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,
"role": roles[0].code if roles else "employee",
"permissions": list(set(permissions)),
"data_scope": "all" if "all" in data_scopes else (
"subordinate_only" if "subordinate_only" in data_scopes else "self_only"
),
}
return await call_next(request)