7.4 KiB
7.4 KiB
许可证验证接口文档
📋 接口概述
接口路径: POST /api/v1/auth/verify
功能: 验证用户的登录 token 是否有效(用于心跳检测)
调用频率: 每 60 秒调用一次
📥 请求参数
Headers
{
"Content-Type": "application/json",
"Authorization": "Bearer {token}"
}
Body (JSON)
{
"username": "string", // 用户名
"device_id": "string", // 设备 ID
"timestamp": 1234567890 // 客户端时间戳(毫秒)
}
示例请求
POST /api/v1/auth/verify HTTP/1.1
Host: 127.0.0.1:8000
Content-Type: application/json
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
{
"username": "zuowei",
"device_id": "065dfbc8-9539-405e-8af0-7cfd56000e6",
"timestamp": 1702828800000
}
📤 响应格式
成功响应(200 OK)
{
"valid": true,
"username": "zuowei",
"expire_date": "2025-12-31T23:59:59Z" // 可选:账户过期时间
}
失败响应 1:Token 无效(401 Unauthorized)
{
"detail": "Token 无效或已过期"
}
失败响应 2:账户已过期(403 Forbidden)
{
"valid": false,
"message": "账户已过期"
}
失败响应 3:会话不存在(404 Not Found)
{
"detail": "会话不存在或已登出"
}
🔧 后端实现示例(FastAPI)
1. 在 Server/app/api/v1/auth.py 添加路由
from fastapi import Depends, HTTPException, status
from pydantic import BaseModel
from app.core.security import get_current_user
from app.db import get_db
from sqlalchemy.orm import Session
from app.models.user import User, UserSession
from datetime import datetime, timezone
class VerifyRequest(BaseModel):
"""验证请求"""
username: str
device_id: str
timestamp: int
class VerifyResponse(BaseModel):
"""验证响应"""
valid: bool
username: str = None
expire_date: str = None
@router.post("/verify", response_model=VerifyResponse)
async def verify_license(
request: VerifyRequest,
current_user: dict = Depends(get_current_user),
db: Session = Depends(get_db)
):
"""
验证许可证(心跳检测)
检查:
1. Token 是否有效(通过 Depends(get_current_user) 自动验证)
2. 用户是否存在
3. 会话是否活跃
4. 账户是否过期
"""
# 1. 查询用户
user = db.query(User).filter(User.username == request.username).first()
if not user:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail="用户不存在"
)
# 2. 检查账户是否过期
if user.expire_date:
expire_dt = user.expire_date
if expire_dt.tzinfo is None:
expire_dt = expire_dt.replace(tzinfo=timezone.utc)
if datetime.now(timezone.utc) > expire_dt:
return VerifyResponse(
valid=False,
username=request.username,
expire_date=user.expire_date.isoformat() if user.expire_date else None
)
# 3. 检查会话是否活跃
session = db.query(UserSession).filter(
UserSession.user_id == user.id,
UserSession.device_id == request.device_id,
UserSession.active == True
).first()
if not session:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail="会话不存在或已登出"
)
# 4. 更新最后活跃时间
session.last_seen_at = datetime.now(timezone.utc)
db.commit()
# 5. 返回验证成功
return VerifyResponse(
valid=True,
username=request.username,
expire_date=user.expire_date.isoformat() if user.expire_date else None
)
2. 更新 Server/app/schemas/auth.py
添加验证相关的 Schema:
class VerifyRequest(BaseModel):
"""验证请求模型"""
username: str
device_id: str
timestamp: int
class VerifyResponse(BaseModel):
"""验证响应模型"""
valid: bool
username: Optional[str] = None
expire_date: Optional[str] = None
🧪 测试验证接口
使用 curl 测试
curl -X POST http://127.0.0.1:8000/api/v1/auth/verify \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_TOKEN_HERE" \
-d '{
"username": "zuowei",
"device_id": "test-device-123",
"timestamp": 1702828800000
}'
预期响应
成功:
{
"valid": true,
"username": "zuowei",
"expire_date": null
}
Token 无效:
{
"detail": "Could not validate credentials"
}
会话不存在:
{
"detail": "会话不存在或已登出"
}
📊 数据库表设计(参考)
确保数据库有以下表和字段:
users 表
CREATE TABLE users (
id INTEGER PRIMARY KEY,
username VARCHAR UNIQUE NOT NULL,
expire_date DATETIME, -- 账户过期时间(NULL = 永久)
...
);
user_sessions 表
CREATE TABLE user_sessions (
id INTEGER PRIMARY KEY,
user_id INTEGER NOT NULL,
device_id VARCHAR NOT NULL,
active BOOLEAN DEFAULT TRUE,
last_seen_at DATETIME, -- 最后活跃时间
...
FOREIGN KEY (user_id) REFERENCES users(id)
);
🔐 安全注意事项
-
Token 验证
- 使用
Depends(get_current_user)确保 Token 有效 - Token 过期自动返回 401
- 使用
-
会话管理
- 验证成功时更新
last_seen_at - 可用于统计在线时长
- 验证成功时更新
-
过期检查
- 支持账户过期时间
- 过期返回
valid: false
-
频率控制
- 前端已做 30 秒缓存,减少请求频率
- 后端可添加 Rate Limiting
🚀 部署检查
添加接口后,确认:
-
✅ 路由已注册
# Server/app/main.py app.include_router(auth.router, prefix=f"{settings.API_V1_STR}/auth") -
✅ 数据库表存在
# 检查 users 和 user_sessions 表 -
✅ Token 验证正常
# 测试登录获取 Token # 测试 verify 接口 -
✅ 前端心跳正常
# 前端每 60 秒调用一次 # 30 秒内不重复验证(有缓存)
📝 完整实现清单
- 添加
VerifyRequest和VerifyResponseSchema - 在
auth.py添加/verify路由 - 实现 Token 验证逻辑
- 实现账户过期检查
- 实现会话活跃检查
- 更新最后活跃时间
- 测试接口(成功、失败、过期等场景)
- 部署到服务器
💡 可选增强
1. 添加限流(Rate Limiting)
from slowapi import Limiter
from slowapi.util import get_remote_address
limiter = Limiter(key_func=get_remote_address)
@router.post("/verify")
@limiter.limit("120/minute") # 每分钟最多 120 次
async def verify_license(...):
...
2. 添加详细日志
import logging
logger = logging.getLogger(__name__)
@router.post("/verify")
async def verify_license(...):
logger.info(f"[Verify] {request.username} from {request.device_id}")
...
3. 返回更多信息
class VerifyResponse(BaseModel):
valid: bool
username: str = None
expire_date: str = None
permissions: list = [] # 用户权限列表
online_time: int = 0 # 在线时长(秒)
实现这个接口后,前端的心跳检测就能正常工作了! ✅