"""路由级鉴权依赖:Bearer JWT → 校验 token → 按 user_id 回查 sys_user → 注入用户。""" from fastapi import Depends, Request from sqlalchemy.ext.asyncio import AsyncSession from config.deps import get_db from model.sys_user import SysUser from repositories.sys_user import SysUserRepo from service.auth import decode_token from utils.exceptions import AuthError, ForbiddenError from service.advisor_agent.audit import write_advisor_audit, audit_action_for_path KNOWLEDGE_OPERATOR_ROLES = {"ADMIN", "KNOWLEDGE_ADMIN", "KNOWLEDGE_OPERATOR", "运营"} async def get_current_user( request: Request, db: AsyncSession = Depends(get_db) ) -> SysUser: header = request.headers.get("Authorization", "") if not header.startswith("Bearer "): raise AuthError() try: user_id = int(decode_token(header.removeprefix("Bearer "))["user_id"]) except Exception: raise AuthError("Token 无效或已过期") user = await SysUserRepo(db).get(user_id) if user is None: raise AuthError("用户不存在") if user.status != "正常": raise ForbiddenError("账号已被禁用或冻结") return user async def require_knowledge_operator(user: SysUser = Depends(get_current_user)) -> SysUser: """Allow only administrators or explicitly assigned knowledge operators.""" if user.user_type == "ADMIN": return user if user.user_type != "EMPLOYEE" or user.employee_role not in KNOWLEDGE_OPERATOR_ROLES: raise ForbiddenError("仅运营人员可以管理知识库") return user async def require_customer(user: SysUser = Depends(get_current_user)) -> SysUser: """Allow only authenticated customer accounts to use client Agent APIs.""" if user.user_type != "CUSTOMER": raise ForbiddenError("仅客户用户可以访问 client_agent") return user async def require_risk_officer(user: SysUser = Depends(get_current_user)) -> SysUser: """仅允许管理员或风控专员执行风控处置/工单操作。""" if user.user_type == "ADMIN": return user if user.user_type != "EMPLOYEE" or user.employee_role != "风控专员": raise ForbiddenError("仅风控专员可执行风控处置") return user async def require_advisor(user: SysUser = Depends(get_current_user)) -> SysUser: """Allow only advisor employees to access the advisor workbench.""" if user.user_type != "EMPLOYEE" or user.employee_role not in {"投顾", "ADMIN"}: raise ForbiddenError("仅投顾人员可以访问投顾工作台") return user async def audited_advisor(request: Request, db: AsyncSession = Depends(get_db)): """Authenticate an advisor Agent request and leave a failure audit trail.""" try: user = await get_current_user(request, db) if user.user_type != "EMPLOYEE" or user.employee_role not in {"投顾", "ADMIN"}: raise ForbiddenError("仅投顾人员可以访问 advisor_agent") yield user except Exception: await write_advisor_audit( db, user=None, action=audit_action_for_path(request.url.path), target=None, trace_id=request.headers.get("X-Trace-Id", ""), status="失败", ) raise