78 lines
2.9 KiB
Python
78 lines
2.9 KiB
Python
"""认证模块路由(/auth/*,对应《03-接口文档》第 3 章)"""
|
|
import redis.asyncio as aioredis
|
|
from fastapi import APIRouter, Depends, Header, Request
|
|
from sqlalchemy.ext.asyncio import AsyncSession
|
|
|
|
from app.core.response import ok
|
|
from app.core.security import decode_token
|
|
from app.database import get_db
|
|
from app.deps import Identity, get_identity, require_user
|
|
from app.redis_client import get_redis
|
|
from app.schemas.auth import (
|
|
EmailSendReq,
|
|
LoginReq,
|
|
PasswordResetReq,
|
|
RefreshReq,
|
|
RegisterReq,
|
|
SmsSendReq,
|
|
)
|
|
from app.services import auth_service
|
|
|
|
router = APIRouter(prefix="/auth", tags=["认证"])
|
|
|
|
|
|
def _client_ip(request: Request) -> str:
|
|
# Nginx 反代后取真实 IP
|
|
return request.headers.get("X-Real-IP") or (request.client.host if request.client else "")
|
|
|
|
|
|
@router.post("/sms/send")
|
|
async def sms_send(req: SmsSendReq, request: Request, db: AsyncSession = Depends(get_db),
|
|
redis: aioredis.Redis = Depends(get_redis)):
|
|
data = await auth_service.send_code(db, redis, "sms", req.phone, req.scene, _client_ip(request))
|
|
return ok(data)
|
|
|
|
|
|
@router.post("/email/send")
|
|
async def email_send(req: EmailSendReq, request: Request, db: AsyncSession = Depends(get_db),
|
|
redis: aioredis.Redis = Depends(get_redis)):
|
|
data = await auth_service.send_code(db, redis, "email", req.email, req.scene, _client_ip(request))
|
|
return ok(data)
|
|
|
|
|
|
@router.post("/register")
|
|
async def register(req: RegisterReq, request: Request, db: AsyncSession = Depends(get_db),
|
|
redis: aioredis.Redis = Depends(get_redis),
|
|
identity: Identity = Depends(get_identity)):
|
|
data = await auth_service.register(db, redis, req, identity.device_id, _client_ip(request))
|
|
return ok(data)
|
|
|
|
|
|
@router.post("/login")
|
|
async def login(req: LoginReq, request: Request, db: AsyncSession = Depends(get_db),
|
|
redis: aioredis.Redis = Depends(get_redis)):
|
|
data = await auth_service.login(db, redis, req, _client_ip(request))
|
|
return ok(data)
|
|
|
|
|
|
@router.post("/token/refresh")
|
|
async def token_refresh(req: RefreshReq, db: AsyncSession = Depends(get_db),
|
|
redis: aioredis.Redis = Depends(get_redis)):
|
|
return ok(await auth_service.refresh(db, redis, req.refresh_token))
|
|
|
|
|
|
@router.post("/logout")
|
|
async def logout(authorization: str = Header(...),
|
|
redis: aioredis.Redis = Depends(get_redis),
|
|
identity: Identity = Depends(require_user)):
|
|
payload = decode_token(authorization.removeprefix("Bearer ").strip())
|
|
await auth_service.logout(redis, identity.user_id, payload.get("jti", ""), int(payload.get("exp", 0)))
|
|
return ok()
|
|
|
|
|
|
@router.post("/password/reset")
|
|
async def password_reset(req: PasswordResetReq, db: AsyncSession = Depends(get_db),
|
|
redis: aioredis.Redis = Depends(get_redis)):
|
|
await auth_service.reset_password(db, redis, req)
|
|
return ok()
|