1aafc28621
引入 JWT 认证、极光一键登录、短信 mock 登录与用户表,并补充技术实施文档与部署配置。 Co-authored-by: Cursor <cursoragent@cursor.com>
59 lines
1.9 KiB
Python
59 lines
1.9 KiB
Python
"""API 层共享依赖:DB session、当前登录用户。"""
|
|
from __future__ import annotations
|
|
|
|
import logging
|
|
from typing import Annotated
|
|
|
|
from fastapi import Depends, HTTPException, status
|
|
from fastapi.security import HTTPAuthorizationCredentials, HTTPBearer
|
|
from sqlalchemy.orm import Session
|
|
|
|
from app.core.security import TokenError, decode_token
|
|
from app.db.session import get_db
|
|
from app.models.user import User
|
|
|
|
logger = logging.getLogger("shagua.deps")
|
|
|
|
# auto_error=True → 没传 Authorization header 时直接 403。但我们想 401,
|
|
# 所以手动 auto_error=False + raise HTTPException
|
|
_bearer = HTTPBearer(auto_error=False, scheme_name="Bearer")
|
|
|
|
|
|
def get_current_user(
|
|
credentials: Annotated[HTTPAuthorizationCredentials | None, Depends(_bearer)],
|
|
db: Annotated[Session, Depends(get_db)],
|
|
) -> User:
|
|
"""从 Authorization: Bearer <access_token> 解出当前 user。
|
|
|
|
失败时统一 401,WWW-Authenticate 头让客户端知道要重新登录。
|
|
"""
|
|
if credentials is None or credentials.scheme.lower() != "bearer":
|
|
raise HTTPException(
|
|
status_code=status.HTTP_401_UNAUTHORIZED,
|
|
detail="missing bearer token",
|
|
headers={"WWW-Authenticate": "Bearer"},
|
|
)
|
|
|
|
try:
|
|
payload = decode_token(credentials.credentials, expected_type="access")
|
|
except TokenError as e:
|
|
raise HTTPException(
|
|
status_code=status.HTTP_401_UNAUTHORIZED,
|
|
detail=str(e),
|
|
headers={"WWW-Authenticate": "Bearer"},
|
|
) from e
|
|
|
|
user_id = int(payload["sub"])
|
|
user = db.get(User, user_id)
|
|
if user is None or user.status != "active":
|
|
raise HTTPException(
|
|
status_code=status.HTTP_401_UNAUTHORIZED,
|
|
detail="user not found or disabled",
|
|
headers={"WWW-Authenticate": "Bearer"},
|
|
)
|
|
return user
|
|
|
|
|
|
CurrentUser = Annotated[User, Depends(get_current_user)]
|
|
DbSession = Annotated[Session, Depends(get_db)]
|