Files
zcglxt/backend/app/api/v1/auth.py

140 lines
3.4 KiB
Python

"""
认证相关API路由
"""
from datetime import datetime
from fastapi import APIRouter, Depends, HTTPException, status, Header
from fastapi.security import HTTPBearer
from sqlalchemy.ext.asyncio import AsyncSession
from app.core.deps import get_db, get_current_user
from app.schemas.user import (
LoginRequest,
LoginResponse,
RefreshTokenRequest,
RefreshTokenResponse,
ChangePasswordRequest,
)
from app.services.auth_service import auth_service
from app.models.user import User
from app.core.response import success_response
from app.core.config import settings
from jose import jwt
import logging
logger = logging.getLogger(__name__)
router = APIRouter()
security = HTTPBearer()
@router.post("/login")
async def login(
credentials: LoginRequest,
db: AsyncSession = Depends(get_db)
):
"""
用户登录
- **username**: 用户名
- **password**: 密码
- **captcha**: 验证码
- **captcha_key**: 验证码UUID
"""
result = await auth_service.login(
db=db,
username=credentials.username,
password=credentials.password,
captcha=credentials.captcha,
captcha_key=credentials.captcha_key
)
return success_response(data=result)
@router.post("/refresh")
async def refresh_token(
token_request: RefreshTokenRequest,
db: AsyncSession = Depends(get_db)
):
"""
刷新访问令牌
- **refresh_token**: 刷新令牌
"""
result = await auth_service.refresh_token(
db=db,
refresh_token=token_request.refresh_token
)
return success_response(data=result)
@router.post("/logout")
async def logout(
current_user: User = Depends(get_current_user),
authorization: str = Header(...),
db: AsyncSession = Depends(get_db)
):
"""
用户登出
"""
from app.utils.redis_client import redis_client
# 提取Token
token = authorization.replace("Bearer ", "")
# 获取Token剩余有效期
try:
payload = jwt.decode(token, settings.SECRET_KEY, algorithms=[settings.ALGORITHM])
exp = payload.get("exp")
if exp:
# 计算剩余秒数
remaining_time = int(exp) - int(datetime.utcnow().timestamp())
if remaining_time > 0:
# 将Token加入黑名单
await redis_client.setex(
f"blacklist:{token}",
remaining_time,
"1"
)
except Exception as e:
logger.error(f"Token黑名单添加失败: {str(e)}")
return success_response(message="登出成功")
@router.put("/change-password")
async def change_password(
password_data: ChangePasswordRequest,
current_user: User = Depends(get_current_user),
db: AsyncSession = Depends(get_db)
):
"""
修改密码
- **old_password**: 旧密码
- **new_password**: 新密码
- **confirm_password**: 确认密码
"""
await auth_service.change_password(
db=db,
user=current_user,
old_password=password_data.old_password,
new_password=password_data.new_password
)
return success_response(message="密码修改成功")
@router.get("/captcha")
async def get_captcha():
"""
获取验证码
返回验证码图片和captcha_key
"""
captcha_data = await auth_service._generate_captcha()
return success_response(data={
"captcha_key": captcha_data["captcha_key"],
"captcha_image": captcha_data["captcha_base64"]
})