This commit is contained in:
2026-05-06 10:28:16 +08:00
parent 06b3e54a39
commit 20451904bd
5 changed files with 111 additions and 24 deletions
+37 -15
View File
@@ -1,8 +1,8 @@
from datetime import datetime, timedelta
from typing import Optional
from jose import JWTError, jwt
from jose import JWTError, ExpiredSignatureError, jwt
import bcrypt
from fastapi import Depends, HTTPException, status
from fastapi import Depends, HTTPException, status, Request
from fastapi.security import OAuth2PasswordBearer
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy import select
@@ -11,6 +11,9 @@ from sqlalchemy.orm import selectinload
from config.settings import settings
from database.database import get_db_session
from models.database import User, UserRole
from utils.logger import get_logger
logger = get_logger(__name__)
pwd_context = bcrypt
@@ -44,30 +47,48 @@ async def get_current_user(
) -> Optional[User]:
if not token:
return None
credentials_exception = HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="无法验证凭据",
headers={"WWW-Authenticate": "Bearer"},
)
try:
payload = jwt.decode(token, settings.SECRET_KEY, algorithms=[settings.ALGORITHM])
username: str = payload.get("sub")
if username is None:
raise credentials_exception
except JWTError:
raise credentials_exception
logger.warning(f"[AUTH] Token 中缺少 sub 字段")
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Token 格式无效:缺少用户标识",
headers={"WWW-Authenticate": "Bearer"},
)
except ExpiredSignatureError:
logger.warning(f"[AUTH] Token 已过期")
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="登录已过期,请重新登录",
headers={"WWW-Authenticate": "Bearer"},
)
except JWTError as e:
logger.warning(f"[AUTH] Token 验证失败: {type(e).__name__}")
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Token 无效,请重新登录",
headers={"WWW-Authenticate": "Bearer"},
)
result = await db_session.execute(
select(User).options(selectinload(User.user_roles).selectinload(UserRole.role)).where(User.username == username)
)
user = result.scalar_one_or_none()
if user is None:
raise credentials_exception
logger.warning(f"[AUTH] Token 有效但用户不存在: {username}")
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="用户账户不存在,请重新登录",
headers={"WWW-Authenticate": "Bearer"},
)
if not user.is_active:
logger.warning(f"[AUTH] 用户已被禁用: {username}")
raise HTTPException(status_code=400, detail="用户已被禁用")
return user
@@ -75,6 +96,7 @@ async def get_current_active_user(
current_user: Optional[User] = Depends(get_current_user)
) -> User:
if not current_user:
logger.warning("[AUTH] 未提供认证信息,拒绝访问")
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="请先登录",