This commit is contained in:
zuowei1216
2025-12-30 14:46:22 +08:00
parent 6c73b31100
commit 12395d8eca
181 changed files with 1255 additions and 114 deletions

View File

@@ -0,0 +1,371 @@
# 许可证验证接口文档
## 📋 接口概述
**接口路径:** `POST /api/v1/auth/verify`
**功能:** 验证用户的登录 token 是否有效(用于心跳检测)
**调用频率:** 每 60 秒调用一次
---
## 📥 请求参数
### Headers
```json
{
"Content-Type": "application/json",
"Authorization": "Bearer {token}"
}
```
### Body (JSON)
```json
{
"username": "string", // 用户名
"device_id": "string", // 设备 ID
"timestamp": 1234567890 // 客户端时间戳(毫秒)
}
```
### 示例请求
```http
POST /api/v1/auth/verify HTTP/1.1
Host: 127.0.0.1:8000
Content-Type: application/json
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
```
---
## 📤 响应格式
### 成功响应200 OK
```json
{
"valid": true,
"username": "zuowei",
"expire_date": "2025-12-31T23:59:59Z" // 可选:账户过期时间
}
```
### 失败响应 1Token 无效401 Unauthorized
```json
{
"detail": "Token 无效或已过期"
}
```
### 失败响应 2账户已过期403 Forbidden
```json
{
"valid": false,
"message": "账户已过期"
}
```
### 失败响应 3会话不存在404 Not Found
```json
{
"detail": "会话不存在或已登出"
}
```
---
## 🔧 后端实现示例FastAPI
### 1. 在 `Server/app/api/v1/auth.py` 添加路由
```python
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
```python
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 测试
```bash
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
}'
```
### 预期响应
**成功:**
```json
{
"valid": true,
"username": "zuowei",
"expire_date": null
}
```
**Token 无效:**
```json
{
"detail": "Could not validate credentials"
}
```
**会话不存在:**
```json
{
"detail": "会话不存在或已登出"
}
```
---
## 📊 数据库表设计(参考)
确保数据库有以下表和字段:
### users 表
```sql
CREATE TABLE users (
id INTEGER PRIMARY KEY,
username VARCHAR UNIQUE NOT NULL,
expire_date DATETIME, -- 账户过期时间NULL = 永久)
...
);
```
### user_sessions 表
```sql
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)
);
```
---
## 🔐 安全注意事项
1. **Token 验证**
- 使用 `Depends(get_current_user)` 确保 Token 有效
- Token 过期自动返回 401
2. **会话管理**
- 验证成功时更新 `last_seen_at`
- 可用于统计在线时长
3. **过期检查**
- 支持账户过期时间
- 过期返回 `valid: false`
4. **频率控制**
- 前端已做 30 秒缓存,减少请求频率
- 后端可添加 Rate Limiting
---
## 🚀 部署检查
添加接口后,确认:
1. ✅ 路由已注册
```python
# Server/app/main.py
app.include_router(auth.router, prefix=f"{settings.API_V1_STR}/auth")
```
2. ✅ 数据库表存在
```bash
# 检查 users 和 user_sessions 表
```
3. ✅ Token 验证正常
```bash
# 测试登录获取 Token
# 测试 verify 接口
```
4. ✅ 前端心跳正常
```
# 前端每 60 秒调用一次
# 30 秒内不重复验证(有缓存)
```
---
## 📝 完整实现清单
- [ ] 添加 `VerifyRequest` 和 `VerifyResponse` Schema
- [ ] 在 `auth.py` 添加 `/verify` 路由
- [ ] 实现 Token 验证逻辑
- [ ] 实现账户过期检查
- [ ] 实现会话活跃检查
- [ ] 更新最后活跃时间
- [ ] 测试接口(成功、失败、过期等场景)
- [ ] 部署到服务器
---
## 💡 可选增强
### 1. 添加限流Rate Limiting
```python
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. 添加详细日志
```python
import logging
logger = logging.getLogger(__name__)
@router.post("/verify")
async def verify_license(...):
logger.info(f"[Verify] {request.username} from {request.device_id}")
...
```
### 3. 返回更多信息
```python
class VerifyResponse(BaseModel):
valid: bool
username: str = None
expire_date: str = None
permissions: list = [] # 用户权限列表
online_time: int = 0 # 在线时长(秒)
```
---
**实现这个接口后,前端的心跳检测就能正常工作了!**
---
**实现这个接口后,前端的心跳检测就能正常工作了!** ✅