stock-ai-agent/backend/app/api/auth.py
2026-02-04 11:18:19 +08:00

159 lines
3.9 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"""
认证API
"""
from fastapi import APIRouter, HTTPException, Depends, Request
from app.models.auth import (
SendCodeRequest, SendCodeResponse,
LoginRequest, LoginResponse,
RefreshTokenResponse, UserInfo
)
from app.models.database import User
from app.services.auth_service import auth_service
from app.services.jwt_service import jwt_service
from app.services.db_service import db_service
from app.middleware.auth_middleware import get_current_user, get_client_ip
from app.utils.logger import logger
router = APIRouter(prefix="/api/auth", tags=["认证"])
@router.post("/send-code", response_model=SendCodeResponse)
async def send_verification_code(
request_data: SendCodeRequest,
request: Request
):
"""
发送验证码
- 同一手机号60秒内只能发送一次
- 同一IP每小时最多发送10次
- 验证码5分钟有效期
"""
try:
client_ip = get_client_ip(request)
db = db_service.get_session()
try:
result = await auth_service.send_verification_code(
db=db,
phone=request_data.phone,
ip_address=client_ip
)
return SendCodeResponse(**result)
finally:
db.close()
except Exception as e:
logger.error(f"发送验证码失败: {e}")
raise HTTPException(status_code=500, detail="发送验证码失败")
@router.post("/login", response_model=LoginResponse)
async def login_with_code(
request_data: LoginRequest,
request: Request
):
"""
验证码登录
- 验证验证码是否正确且未过期
- 用户不存在则自动注册
- 生成JWT token7天有效期
- 更新最后登录时间
"""
try:
client_ip = get_client_ip(request)
db = db_service.get_session()
try:
result = await auth_service.login_with_code(
db=db,
phone=request_data.phone,
code=request_data.code,
ip_address=client_ip
)
if not result["success"]:
return LoginResponse(
success=False,
message=result["message"]
)
return LoginResponse(
success=True,
token=result["token"],
user=UserInfo(**result["user"])
)
finally:
db.close()
except Exception as e:
logger.error(f"登录失败: {e}")
raise HTTPException(status_code=500, detail="登录失败")
@router.post("/refresh", response_model=RefreshTokenResponse)
async def refresh_token(
current_user: User = Depends(get_current_user)
):
"""
刷新Token
需要提供有效的JWT token
"""
try:
# 生成新的token
new_token = jwt_service.create_access_token(
current_user.id,
current_user.phone
)
return RefreshTokenResponse(
success=True,
token=new_token
)
except Exception as e:
logger.error(f"刷新token失败: {e}")
raise HTTPException(status_code=500, detail="刷新token失败")
@router.get("/me", response_model=UserInfo)
async def get_current_user_info(
current_user: User = Depends(get_current_user)
):
"""
获取当前用户信息
需要提供有效的JWT token
"""
# 手机号脱敏
masked_phone = f"{current_user.phone[:3]}****{current_user.phone[-4:]}"
return UserInfo(
id=current_user.id,
phone=masked_phone,
created_at=current_user.created_at,
last_login_at=current_user.last_login_at
)
@router.post("/logout")
async def logout(
current_user: User = Depends(get_current_user)
):
"""
登出
主要在前端清除token后端记录日志
"""
logger.info(f"用户登出: {current_user.phone}")
return {
"success": True,
"message": "已登出"
}