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
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)
|