"""FastAPI 依赖:JWT 会话鉴权、API Key 鉴权。""" import datetime as dt from typing import Optional from fastapi import Depends, HTTPException, status, Header from fastapi.security import HTTPBearer, HTTPAuthorizationCredentials from sqlalchemy.orm import Session from .database import get_db from .models import User, ApiKey from .security import decode_access_token bearer_scheme = HTTPBearer(auto_error=False) def get_current_user( creds: Optional[HTTPAuthorizationCredentials] = Depends(bearer_scheme), db: Session = Depends(get_db), ) -> User: """用会话 JWT 鉴权(页面接口用)。""" if creds is None or creds.scheme.lower() != "bearer": raise HTTPException(status.HTTP_401_UNAUTHORIZED, "未携带 Bearer token") user_id = decode_access_token(creds.credentials) if user_id is None: raise HTTPException(status.HTTP_401_UNAUTHORIZED, "token 无效或已过期") user = db.query(User).get(user_id) if user is None: raise HTTPException(status.HTTP_401_UNAUTHORIZED, "用户不存在") return user def get_user_from_api_key( x_api_key: str = Header(default="", alias="X-API-Key"), db: Session = Depends(get_db), ) -> User: """用 X-API-Key 鉴权(外部调用接口用)。 流程:明文 key → SHA-256 → 查库 → 命中且未吊销即通过。 """ if not x_api_key: raise HTTPException(status.HTTP_401_UNAUTHORIZED, "缺少 X-API-Key") key_hash = ApiKey.hash_key(x_api_key) api_key = ( db.query(ApiKey).filter(ApiKey.key_hash == key_hash).first() ) if api_key is None or api_key.revoked: raise HTTPException(status.HTTP_401_UNAUTHORIZED, "API Key 无效或已吊销") api_key.last_used_at = dt.datetime.utcnow() db.commit() return api_key.user