# core/deps.py # 认证与权限依赖:从请求头解析 JWT -> 加载用户 -> 角色级 RBAC 校验 from fastapi import Depends, HTTPException, status from fastapi.security import HTTPAuthorizationCredentials, HTTPBearer import jwt from sqlalchemy.orm import Session from core.security import decode_access_token from database import get_db from model.user import User # 自动从 Authorization: Bearer 中提取 token _bearer_scheme = HTTPBearer(auto_error=False) def get_current_user( credentials: HTTPAuthorizationCredentials = Depends(_bearer_scheme), db: Session = Depends(get_db), ) -> User: """ 解析 JWT 并返回当前登录用户(model.user.User 对象) 未登录 / token 无效 / 用户不存在 均抛 401 """ if credentials is None: raise HTTPException( status_code=status.HTTP_401_UNAUTHORIZED, detail="未登录,请先获取 token", headers={"WWW-Authenticate": "Bearer"}, ) try: payload = decode_access_token(credentials.credentials) except jwt.ExpiredSignatureError: raise HTTPException(status_code=401, detail="token 已过期,请重新登录") except jwt.InvalidTokenError: raise HTTPException(status_code=401, detail="token 无效") user_id = int(payload["sub"]) user = ( db.query(User) .filter(User.user_id == user_id, User.is_deleted == 0) .first() ) if user is None: raise HTTPException(status_code=401, detail="用户不存在或已被禁用") return user def require_roles(*roles: str): """ 角色级 RBAC 依赖工厂。 用法:user: User = Depends(require_roles("admin", "teacher")) """ def checker(user: User = Depends(get_current_user)) -> User: if user.role not in roles: raise HTTPException( status_code=status.HTTP_403_FORBIDDEN, detail=f"权限不足,需要角色:{' / '.join(roles)},当前角色:{user.role}", ) return user return checker def get_teacher_class_ids(db: Session, teacher_id: int) -> list[int]: """获取某教师所带班级 ID 列表(用于资源归属校验)""" from model.teachers import Teacher rows = ( db.query(Teacher.class_id) .filter(Teacher.teacher_id == teacher_id, Teacher.is_deleted == 0) .all() ) return [r[0] for r in rows]