Files
stu_teacher/core/deps.py
T

74 lines
2.4 KiB
Python

# 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> 中提取 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]