first commit
This commit is contained in:
+78
@@ -0,0 +1,78 @@
|
||||
from datetime import datetime, timezone
|
||||
from typing import Annotated
|
||||
|
||||
from fastapi import Depends, HTTPException, status
|
||||
from fastapi.security import HTTPAuthorizationCredentials, HTTPBearer
|
||||
from sqlalchemy import select
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
from sqlalchemy.orm import selectinload
|
||||
|
||||
from app.database import get_db
|
||||
from app.models import RefreshSession, User
|
||||
from app.security import decode_access_token
|
||||
|
||||
|
||||
DbSession = Annotated[AsyncSession, Depends(get_db)]
|
||||
bearer = HTTPBearer(auto_error=False)
|
||||
|
||||
|
||||
async def _resolve_user(
|
||||
credentials: HTTPAuthorizationCredentials,
|
||||
db: AsyncSession,
|
||||
) -> User:
|
||||
if credentials.scheme.lower() != "bearer":
|
||||
raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail="无效的认证方式")
|
||||
try:
|
||||
payload = decode_access_token(credentials.credentials)
|
||||
except ValueError as exc:
|
||||
raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail=str(exc)) from exc
|
||||
|
||||
result = await db.execute(
|
||||
select(User)
|
||||
.join(
|
||||
RefreshSession,
|
||||
(RefreshSession.id == payload.session_id)
|
||||
& (RefreshSession.user_id == User.id),
|
||||
)
|
||||
.options(selectinload(User.profile))
|
||||
.where(
|
||||
User.id == payload.user_id,
|
||||
RefreshSession.revoked_at.is_(None),
|
||||
RefreshSession.expires_at > datetime.now(timezone.utc),
|
||||
)
|
||||
)
|
||||
user = result.scalar_one_or_none()
|
||||
if not user:
|
||||
raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail="登录状态已失效")
|
||||
if user.profile.is_disabled:
|
||||
raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail="账号已被禁用")
|
||||
return user
|
||||
|
||||
|
||||
async def get_current_user(
|
||||
db: DbSession,
|
||||
credentials: Annotated[HTTPAuthorizationCredentials | None, Depends(bearer)],
|
||||
) -> User:
|
||||
if credentials is None:
|
||||
raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail="请先登录")
|
||||
return await _resolve_user(credentials, db)
|
||||
|
||||
|
||||
async def get_optional_user(
|
||||
db: DbSession,
|
||||
credentials: Annotated[HTTPAuthorizationCredentials | None, Depends(bearer)],
|
||||
) -> User | None:
|
||||
if credentials is None:
|
||||
return None
|
||||
return await _resolve_user(credentials, db)
|
||||
|
||||
|
||||
async def get_admin_user(user: Annotated[User, Depends(get_current_user)]) -> User:
|
||||
if user.profile.role != "admin":
|
||||
raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail="需要管理员权限")
|
||||
return user
|
||||
|
||||
|
||||
CurrentUser = Annotated[User, Depends(get_current_user)]
|
||||
OptionalUser = Annotated[User | None, Depends(get_optional_user)]
|
||||
AdminUser = Annotated[User, Depends(get_admin_user)]
|
||||
Reference in New Issue
Block a user