feat: 初始化考培练系统项目

- 从服务器拉取完整代码
- 按框架规范整理项目结构
- 配置 Drone CI 测试环境部署
- 包含后端(FastAPI)、前端(Vue3)、管理端

技术栈: Vue3 + TypeScript + FastAPI + MySQL
This commit is contained in:
111
2026-01-24 19:33:28 +08:00
commit 998211c483
1197 changed files with 228429 additions and 0 deletions

View File

@@ -0,0 +1,185 @@
openapi: 3.0.0
info:
title: 认证授权模块API
version: 1.0.0
description: 负责用户认证、授权和Token管理
paths:
/api/v1/auth/login:
post:
summary: 用户登录
tags: [认证]
requestBody:
required: true
content:
application/x-www-form-urlencoded:
schema:
type: object
properties:
username:
type: string
description: 用户名或邮箱
password:
type: string
description: 密码
required:
- username
- password
responses:
200:
description: 登录成功
content:
application/json:
schema:
$ref: '#/components/schemas/TokenResponse'
400:
description: 请求参数错误
401:
description: 用户名或密码错误
403:
description: 账号已被禁用
/api/v1/auth/register:
post:
summary: 用户注册
tags: [认证]
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/UserRegister'
responses:
201:
description: 注册成功
content:
application/json:
schema:
$ref: '#/components/schemas/TokenResponse'
400:
description: 参数验证失败
409:
description: 用户名或邮箱已存在
/api/v1/auth/logout:
post:
summary: 用户登出
tags: [认证]
security:
- bearerAuth: []
responses:
200:
description: 登出成功
401:
description: 未授权
/api/v1/auth/refresh:
post:
summary: 刷新Token
tags: [认证]
requestBody:
required: true
content:
application/json:
schema:
type: object
properties:
refresh_token:
type: string
required:
- refresh_token
responses:
200:
description: 刷新成功
content:
application/json:
schema:
$ref: '#/components/schemas/TokenResponse'
401:
description: 刷新Token无效
/api/v1/auth/reset-password:
post:
summary: 重置密码请求
tags: [认证]
requestBody:
required: true
content:
application/json:
schema:
type: object
properties:
email:
type: string
format: email
required:
- email
responses:
200:
description: 重置邮件已发送
404:
description: 邮箱不存在
components:
schemas:
UserRegister:
type: object
properties:
username:
type: string
minLength: 3
maxLength: 20
pattern: '^[a-zA-Z0-9_-]+$'
email:
type: string
format: email
password:
type: string
minLength: 8
confirm_password:
type: string
required:
- username
- email
- password
- confirm_password
TokenResponse:
type: object
properties:
code:
type: integer
example: 200
message:
type: string
example: success
data:
type: object
properties:
access_token:
type: string
refresh_token:
type: string
token_type:
type: string
example: bearer
expires_in:
type: integer
example: 1800
user:
type: object
properties:
id:
type: integer
username:
type: string
email:
type: string
role:
type: string
securitySchemes:
bearerAuth:
type: http
scheme: bearer
bearerFormat: JWT

View File

@@ -0,0 +1,119 @@
# Agent-Auth 开发检查清单
## 开发前准备
- [ ] 阅读并理解 `prompt.md` 中的所有要求
- [ ] 熟悉 `context.md` 中的项目结构和依赖
- [ ] 查看 `api_contract.yaml` 了解API规范
- [ ] 设置开发环境,安装所有依赖
- [ ] 创建 feature/auth 分支
## 核心功能开发
### 1. 数据库模型
- [ ] 创建 `app/models/user.py` 用户模型
- [ ] 继承 BaseModel 和 AuditMixin
- [ ] 添加必要的索引
- [ ] 创建数据库迁移脚本
### 2. Schema定义
- [ ] 创建 `app/schemas/auth.py`
- [ ] 定义 UserLogin schema
- [ ] 定义 UserRegister schema
- [ ] 定义 Token schema
- [ ] 添加输入验证规则
### 3. 安全功能
- [ ] 完善 `app/core/security.py`
- [ ] 实现密码加密函数
- [ ] 实现密码验证函数
- [ ] 实现JWT Token生成
- [ ] 实现JWT Token验证
### 4. 依赖注入
- [ ] 创建/完善 `app/api/deps.py`
- [ ] 实现 get_current_user
- [ ] 实现 get_current_active_user
- [ ] 实现角色检查器require_admin等
### 5. 业务服务
- [ ] 创建 `app/services/auth_service.py`
- [ ] 实现用户认证逻辑
- [ ] 实现用户创建逻辑
- [ ] 实现Token管理逻辑
- [ ] 添加错误处理
### 6. API路由
- [ ] 创建 `app/api/v1/auth.py`
- [ ] 实现登录端点
- [ ] 实现注册端点
- [ ] 实现登出端点
- [ ] 实现Token刷新端点
- [ ] 实现密码重置端点
### 7. 中间件和异常
- [ ] 实现认证中间件
- [ ] 添加请求限流
- [ ] 处理认证异常
## 测试开发
### 单元测试
- [ ] 创建 `tests/unit/test_auth_service.py`
- [ ] 测试密码加密和验证
- [ ] 测试Token生成和验证
- [ ] 测试用户认证逻辑
- [ ] 测试用户创建逻辑
### 集成测试
- [ ] 创建 `tests/integration/test_auth_api.py`
- [ ] 测试登录流程
- [ ] 测试注册流程
- [ ] 测试Token刷新
- [ ] 测试权限验证
### 性能测试
- [ ] 测试登录响应时间
- [ ] 测试Token验证性能
- [ ] 测试并发登录
## 安全检查
- [ ] 密码使用bcrypt加密
- [ ] Token设置合理过期时间
- [ ] 实现登录失败限制
- [ ] 防止暴力破解
- [ ] SQL注入防护
- [ ] XSS防护
## 文档更新
- [ ] 更新API文档
- [ ] 添加使用示例
- [ ] 更新README
- [ ] 编写部署说明
## 代码质量
- [ ] 运行 `make format` 格式化代码
- [ ] 运行 `make lint` 检查代码风格
- [ ] 运行 `make type-check` 类型检查
- [ ] 运行 `make test` 所有测试通过
- [ ] 代码覆盖率 > 80%
## 集成验证
- [ ] 与其他模块集成测试
- [ ] 验证依赖注入正常工作
- [ ] 验证中间件正常拦截
- [ ] 验证日志记录完整
## 提交前确认
- [ ] 所有功能已实现
- [ ] 所有测试通过
- [ ] 文档已更新
- [ ] 代码已审查
- [ ] 没有硬编码的密钥
- [ ] 没有调试代码
- [ ] commit信息符合规范
## 部署准备
- [ ] 环境变量已配置
- [ ] 生产配置已准备
- [ ] 性能优化已完成
- [ ] 监控指标已添加

View File

@@ -0,0 +1,137 @@
# Agent-Auth 上下文信息
## 重要规划文档
在开始开发前,请确保你已经理解以下关键文档:
- `../../协作机制设计.md` - 特别是全局上下文(GlobalContext)和服务间调用机制
- `../../模块分工指南.md` - 了解Auth模块的职责边界第2.1节)
- `../../开发规范文档.md` - 编码标准和API设计规范
- `../../统一基础代码.md` - 可复用的代码模板
## 项目位置
- 项目根目录: `/Users/nongjun/Desktop/Ai公司/本地开发与测试/kaopeilian-backend/`
- 你的工作目录: `app/api/v1/auth.py`, `app/core/security.py`, `app/services/auth_service.py`
## 重要依赖文件
### 1. 基础模型 (`app/models/base.py`)
已提供BaseModel, SoftDeleteMixin, AuditMixin等基类
### 2. 用户模型 (`app/models/user.py`) - 需要你创建
```python
from sqlalchemy import Column, String, Boolean, Enum
from app.models.base import BaseModel, AuditMixin
class User(BaseModel, AuditMixin):
__tablename__ = "users"
username = Column(String(50), unique=True, nullable=False, index=True)
email = Column(String(100), unique=True, nullable=False, index=True)
password_hash = Column(String(200), nullable=False)
is_active = Column(Boolean, default=True)
is_superuser = Column(Boolean, default=False)
role = Column(String(20), default="trainee") # trainee, manager, admin
```
### 3. 基础Schema (`app/schemas/base.py`)
已提供BaseSchema, ResponseModel, ErrorResponse等基类
### 4. 异常处理 (`app/core/exceptions.py`)
已定义所有标准异常类
### 5. 日志系统 (`app/core/logger.py`)
已配置结构化日志
### 6. 配置管理 (`app/config/settings.py`)
关键配置项:
- SECRET_KEY - JWT密钥
- ALGORITHM - JWT算法默认HS256
- ACCESS_TOKEN_EXPIRE_MINUTES - 访问Token过期时间默认30分钟
- REFRESH_TOKEN_EXPIRE_DAYS - 刷新Token过期时间默认7天
## 数据库表结构
```sql
CREATE TABLE users (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
username VARCHAR(50) UNIQUE NOT NULL,
email VARCHAR(100) UNIQUE NOT NULL,
password_hash VARCHAR(200) NOT NULL,
is_active BOOLEAN DEFAULT TRUE,
is_superuser BOOLEAN DEFAULT FALSE,
role VARCHAR(20) DEFAULT 'trainee',
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
created_by BIGINT,
updated_by BIGINT,
INDEX idx_username (username),
INDEX idx_email (email)
);
```
## 环境变量
```bash
# .env 文件中的认证相关配置
SECRET_KEY="your-secret-key-here-must-be-at-least-32-chars"
ALGORITHM="HS256"
ACCESS_TOKEN_EXPIRE_MINUTES=30
REFRESH_TOKEN_EXPIRE_DAYS=7
```
## 测试账号
用于开发测试的默认账号:
- 超级管理员: superadmin / Superadmin123!
- 系统管理员: admin / Admin123!
- 测试学员: testuser / TestPass123!
## 错误码约定
- 1001: 用户名或密码错误
- 1002: 账号已被禁用
- 1003: Token无效或已过期
- 1004: 权限不足
- 1005: 用户名已存在
- 1006: 邮箱已存在
## 关键流程
### 登录流程
1. 接收用户名和密码
2. 验证用户身份
3. 检查账号状态
4. 生成访问Token和刷新Token
5. 返回Token信息
### 注册流程
1. 验证输入数据
2. 检查用户名和邮箱唯一性
3. 加密密码
4. 创建用户记录
5. 自动登录并返回Token
### Token刷新流程
1. 验证刷新Token
2. 检查Token是否在黑名单
3. 生成新的访问Token
4. 可选轮换刷新Token
## 安全最佳实践
1. 使用bcrypt加密密码cost factor设为12
2. JWT Token使用RS256算法生产环境
3. 实现Token黑名单机制使用Redis
4. 登录失败5次锁定账号15分钟
5. 敏感操作记录审计日志

View File

@@ -0,0 +1,93 @@
# Agent-Auth 依赖关系
## 依赖概览
Agent-Auth是基础模块**不依赖其他业务模块**,但依赖系统基础设施。
## 输入依赖
### 1. 系统基础设施
- `app/config/settings.py` - 系统配置
- `app/config/database.py` - 数据库连接
- `app/core/logger.py` - 日志系统
- `app/models/base.py` - 基础模型类
- `app/schemas/base.py` - 基础Schema类
### 2. 第三方库
- `fastapi` - Web框架
- `sqlalchemy` - ORM
- `passlib[bcrypt]` - 密码加密
- `python-jose[cryptography]` - JWT处理
- `redis` - 缓存用于Token黑名单
### 3. 环境变量
```bash
SECRET_KEY=必需
ALGORITHM=可选(默认HS256)
ACCESS_TOKEN_EXPIRE_MINUTES=可选(默认30)
REFRESH_TOKEN_EXPIRE_DAYS=可选(默认7)
```
## 输出接口
### 1. 依赖注入函数
其他所有模块都会使用这些函数:
```python
# app/api/deps.py 或 app/core/deps.py
async def get_current_user() -> User
async def get_current_active_user() -> User
async def get_optional_current_user() -> Optional[User]
# 角色检查器
require_admin = RoleChecker(["admin"])
require_manager = RoleChecker(["admin", "manager"])
require_trainer = RoleChecker(["admin", "manager", "trainer"])
```
### 2. 安全工具函数
```python
# app/core/security.py
def verify_password(plain_password: str, hashed_password: str) -> bool
def get_password_hash(password: str) -> str
def create_access_token(subject: int, **kwargs) -> str
def create_refresh_token(subject: int) -> str
def verify_token(token: str) -> dict
```
### 3. 数据模型
```python
# app/models/user.py
class User(BaseModel, AuditMixin):
# 被所有其他模块引用的用户模型
pass
```
### 4. API端点
```
POST /api/v1/auth/login
POST /api/v1/auth/register
POST /api/v1/auth/logout
POST /api/v1/auth/refresh
POST /api/v1/auth/reset-password
```
## 被依赖情况
以下模块依赖Auth模块
- **所有模块** - 使用认证和权限检查
- Agent-User - 使用User模型
- Agent-Course - 使用get_current_user
- Agent-Exam - 使用get_current_user
- Agent-Training - 使用get_current_user
- Agent-Analytics - 使用权限检查
- Agent-Admin - 使用require_admin
## 接口稳定性
⚠️ **关键接口,需保持稳定**
- 修改认证逻辑会影响所有模块
- Token格式变更需要通知所有模块
- User模型字段变更需要评估影响
## 测试依赖
- 需要模拟Redis服务
- 需要测试数据库
- 需要模拟邮件服务(密码重置)

View File

@@ -0,0 +1,201 @@
"""
认证API路由示例代码
"""
from fastapi import APIRouter, Depends, HTTPException, status
from fastapi.security import OAuth2PasswordRequestForm
from sqlalchemy.ext.asyncio import AsyncSession
from app.api.deps import get_db
from app.core.exceptions import UnauthorizedError, ConflictError
from app.schemas.auth import UserRegister, Token, PasswordReset
from app.schemas.base import ResponseModel
from app.services.auth_service import AuthService
router = APIRouter(prefix="/auth", tags=["认证"])
@router.post("/login", response_model=ResponseModel[Token], summary="用户登录")
async def login(
form_data: OAuth2PasswordRequestForm = Depends(),
db: AsyncSession = Depends(get_db)
):
"""
用户登录接口
- **username**: 用户名或邮箱
- **password**: 密码
返回访问令牌和刷新令牌
"""
auth_service = AuthService(db)
# 验证用户
user = await auth_service.authenticate_user(
username=form_data.username,
password=form_data.password
)
if not user:
raise UnauthorizedError("用户名或密码错误")
# 创建Token
token = await auth_service.create_tokens(user)
return ResponseModel(
code=200,
message="登录成功",
data=token
)
@router.post("/register", response_model=ResponseModel[Token], status_code=status.HTTP_201_CREATED)
async def register(
user_data: UserRegister,
db: AsyncSession = Depends(get_db)
):
"""
用户注册接口
注册成功后自动登录返回Token
"""
# 验证密码一致性
if user_data.password != user_data.confirm_password:
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail="两次输入的密码不一致"
)
auth_service = AuthService(db)
try:
# 创建用户
user = await auth_service.create_user(user_data)
# 自动登录
token = await auth_service.create_tokens(user)
return ResponseModel(
code=201,
message="注册成功",
data=token
)
except ConflictError as e:
raise HTTPException(
status_code=status.HTTP_409_CONFLICT,
detail=str(e)
)
@router.post("/logout", response_model=ResponseModel)
async def logout(
token: str = Depends(get_current_token),
db: AsyncSession = Depends(get_db)
):
"""
用户登出接口
将当前Token加入黑名单
"""
auth_service = AuthService(db)
await auth_service.logout(token)
return ResponseModel(
code=200,
message="登出成功"
)
@router.post("/refresh", response_model=ResponseModel[Token])
async def refresh_token(
refresh_token: str,
db: AsyncSession = Depends(get_db)
):
"""
刷新访问令牌
使用刷新令牌获取新的访问令牌
"""
auth_service = AuthService(db)
try:
token = await auth_service.refresh_access_token(refresh_token)
return ResponseModel(
code=200,
message="刷新成功",
data=token
)
except UnauthorizedError:
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="刷新令牌无效或已过期"
)
@router.post("/reset-password/request", response_model=ResponseModel)
async def request_password_reset(
email: str,
db: AsyncSession = Depends(get_db)
):
"""
请求重置密码
向用户邮箱发送重置链接
"""
auth_service = AuthService(db)
# 查找用户
user = await auth_service.get_user_by_email(email)
if not user:
# 为了安全,即使用户不存在也返回成功
return ResponseModel(
code=200,
message="如果邮箱存在,重置链接已发送"
)
# 生成重置令牌
reset_token = await auth_service.create_password_reset_token(user)
# TODO: 发送邮件
# await send_reset_email(email, reset_token)
return ResponseModel(
code=200,
message="如果邮箱存在,重置链接已发送"
)
@router.post("/reset-password/confirm", response_model=ResponseModel)
async def reset_password(
reset_data: PasswordReset,
db: AsyncSession = Depends(get_db)
):
"""
确认重置密码
使用重置令牌设置新密码
"""
auth_service = AuthService(db)
try:
await auth_service.reset_password(
token=reset_data.token,
new_password=reset_data.new_password
)
return ResponseModel(
code=200,
message="密码重置成功"
)
except UnauthorizedError:
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail="重置令牌无效或已过期"
)
# 辅助函数
async def get_current_token(
authorization: str = Depends(oauth2_scheme)
) -> str:
"""获取当前请求的Token"""
return authorization

View File

@@ -0,0 +1,163 @@
"""
认证服务示例代码
"""
from typing import Optional
from datetime import datetime, timedelta
from sqlalchemy import select
from sqlalchemy.ext.asyncio import AsyncSession
from fastapi import HTTPException, status
from app.core.security import verify_password, get_password_hash, create_access_token, create_refresh_token
from app.core.exceptions import UnauthorizedError, ConflictError, ForbiddenError
from app.core.logger import logger
from app.models.user import User
from app.schemas.auth import UserRegister, Token
class AuthService:
"""认证服务类"""
def __init__(self, db: AsyncSession):
self.db = db
async def authenticate_user(self, username: str, password: str) -> Optional[User]:
"""
验证用户身份
Args:
username: 用户名或邮箱
password: 密码
Returns:
验证成功返回User对象失败返回None
"""
# 查询用户(支持用户名或邮箱登录)
query = select(User).where(
(User.username == username) | (User.email == username)
)
result = await self.db.execute(query)
user = result.scalar_one_or_none()
if not user:
logger.warning("登录失败:用户不存在", username=username)
return None
# 验证密码
if not verify_password(password, user.password_hash):
logger.warning("登录失败:密码错误", user_id=user.id, username=username)
# TODO: 记录失败次数,实现账号锁定
return None
# 检查账号状态
if not user.is_active:
logger.warning("登录失败:账号已禁用", user_id=user.id, username=username)
raise ForbiddenError("账号已被禁用")
logger.info("用户登录成功", user_id=user.id, username=user.username)
return user
async def create_user(self, user_data: UserRegister) -> User:
"""
创建新用户
Args:
user_data: 用户注册数据
Returns:
创建的用户对象
Raises:
ConflictError: 用户名或邮箱已存在
"""
# 检查用户名是否存在
query = select(User).where(User.username == user_data.username)
result = await self.db.execute(query)
if result.scalar_one_or_none():
raise ConflictError("用户名已存在")
# 检查邮箱是否存在
query = select(User).where(User.email == user_data.email)
result = await self.db.execute(query)
if result.scalar_one_or_none():
raise ConflictError("邮箱已存在")
# 创建用户
user = User(
username=user_data.username,
email=user_data.email,
password_hash=get_password_hash(user_data.password),
is_active=True,
is_superuser=False,
role="trainee" # 默认角色为学员
)
self.db.add(user)
await self.db.commit()
await self.db.refresh(user)
logger.info("用户注册成功", user_id=user.id, username=user.username)
return user
async def create_tokens(self, user: User) -> Token:
"""
为用户创建访问令牌和刷新令牌
Args:
user: 用户对象
Returns:
Token对象
"""
# 创建访问令牌
access_token = create_access_token(
subject=user.id,
role=user.role,
username=user.username
)
# 创建刷新令牌
refresh_token = create_refresh_token(subject=user.id)
return Token(
access_token=access_token,
refresh_token=refresh_token,
token_type="bearer",
expires_in=1800, # 30分钟
user={
"id": user.id,
"username": user.username,
"email": user.email,
"role": user.role
}
)
async def logout(self, token: str) -> None:
"""
用户登出将token加入黑名单
Args:
token: 要失效的token
"""
# TODO: 将token加入Redis黑名单
# redis_key = f"blacklist:{token}"
# await redis.setex(redis_key, 3600, "1") # 设置1小时过期
logger.info("用户登出成功")
async def refresh_access_token(self, refresh_token: str) -> Token:
"""
使用刷新令牌获取新的访问令牌
Args:
refresh_token: 刷新令牌
Returns:
新的Token对象
"""
# TODO: 验证刷新令牌
# TODO: 检查是否在黑名单
# TODO: 生成新的访问令牌
# TODO: 可选 - 轮换刷新令牌
pass

View File

@@ -0,0 +1,188 @@
# Agent-Auth 提示词
## 基础规范引用
**重要**: 开始开发前,你必须先阅读并严格遵循以下文件:
- `00-通用基础/base_prompt.md` - 通用开发规范(代码格式、错误处理、日志规范等)
- `00-通用基础/project_structure.md` - 项目目录结构说明
## 你的角色
你是Agent-Auth负责考培练系统的**认证授权模块**开发。你的代码将成为整个系统的安全基石,其他所有模块都将依赖你的认证服务。
## 核心职责
1. 实现用户登录、注册、登出功能
2. 管理JWT Token的生成和验证
3. 提供权限检查中间件和依赖注入
4. 实现密码重置和账号激活功能
5. 确保系统的安全性
## 你需要开发的文件
### 1. API路由 (`app/api/v1/auth.py`)
```python
from fastapi import APIRouter, Depends, HTTPException, status
from fastapi.security import OAuth2PasswordRequestForm
from sqlalchemy.ext.asyncio import AsyncSession
from app.core.deps import get_db
from app.services.auth_service import AuthService
from app.schemas.auth import Token, UserLogin, UserRegister
from app.schemas.base import ResponseModel
router = APIRouter()
@router.post("/login", response_model=ResponseModel[Token])
async def login(
form_data: OAuth2PasswordRequestForm = Depends(),
db: AsyncSession = Depends(get_db)
):
"""用户登录"""
# 实现登录逻辑
pass
@router.post("/register", response_model=ResponseModel[Token])
async def register(
user_data: UserRegister,
db: AsyncSession = Depends(get_db)
):
"""用户注册"""
# 实现注册逻辑
pass
@router.post("/logout")
async def logout():
"""用户登出"""
# 实现登出逻辑
pass
@router.post("/refresh", response_model=ResponseModel[Token])
async def refresh_token(refresh_token: str):
"""刷新Token"""
# 实现Token刷新逻辑
pass
@router.post("/reset-password")
async def reset_password(email: str):
"""重置密码"""
# 实现密码重置逻辑
pass
```
### 2. 安全核心功能 (`app/core/security.py`)
已在基础代码中部分实现,你需要完善:
- 密码加密和验证
- JWT Token生成和验证
- 权限验证装饰器
### 3. 认证依赖注入 (`app/core/deps.py` 或 `app/api/deps.py`)
```python
async def get_current_user(
db: AsyncSession = Depends(get_db),
token: str = Depends(oauth2_scheme)
) -> User:
"""获取当前登录用户"""
# 实现逻辑
pass
async def require_admin(user: User = Depends(get_current_user)) -> User:
"""需要管理员权限"""
# 实现逻辑
pass
```
### 4. Schema定义 (`app/schemas/auth.py`)
```python
from pydantic import EmailStr, Field
from app.schemas.base import BaseSchema
class UserLogin(BaseSchema):
username: str = Field(..., description="用户名或邮箱")
password: str = Field(..., description="密码")
class UserRegister(BaseSchema):
username: str = Field(..., min_length=3, max_length=20)
email: EmailStr
password: str = Field(..., min_length=8)
confirm_password: str
class Token(BaseSchema):
access_token: str
refresh_token: str
token_type: str = "bearer"
expires_in: int
```
### 5. 认证服务 (`app/services/auth_service.py`)
```python
from app.services.base_service import BaseService
class AuthService:
def __init__(self, db: AsyncSession):
self.db = db
async def authenticate_user(self, username: str, password: str):
"""验证用户身份"""
pass
async def create_user(self, user_data: UserRegister):
"""创建新用户"""
pass
async def create_tokens(self, user_id: int):
"""创建访问令牌和刷新令牌"""
pass
```
### 6. 测试用例 (`tests/unit/test_auth.py`)
```python
import pytest
from app.services.auth_service import AuthService
@pytest.mark.asyncio
async def test_user_registration(db_session):
"""测试用户注册"""
pass
@pytest.mark.asyncio
async def test_user_login(db_session):
"""测试用户登录"""
pass
@pytest.mark.asyncio
async def test_token_refresh(db_session):
"""测试Token刷新"""
pass
```
## 与其他模块的接口
### 提供给其他模块的功能
1. `get_current_user` - 获取当前登录用户
2. `require_admin` - 需要管理员权限
3. `require_manager` - 需要管理者权限
4. `create_access_token` - 创建访问令牌
5. `verify_password` - 验证密码
6. `get_password_hash` - 获取密码哈希
### API端点
- POST `/api/v1/auth/login` - 用户登录
- POST `/api/v1/auth/register` - 用户注册
- POST `/api/v1/auth/logout` - 用户登出
- POST `/api/v1/auth/refresh` - 刷新Token
- POST `/api/v1/auth/reset-password` - 重置密码
## 安全要求
1. 密码必须使用bcrypt加密存储
2. JWT Token必须设置合理的过期时间
3. 刷新Token必须与访问Token分开存储
4. 实现登录失败次数限制
5. 敏感操作需要二次验证
## 性能要求
1. 登录响应时间 < 200ms
2. Token验证时间 < 50ms
3. 合理使用Redis缓存Token黑名单
## 参考资源
- FastAPI Security文档: https://fastapi.tiangolo.com/tutorial/security/
- JWT最佳实践: https://tools.ietf.org/html/rfc8725
- OWASP认证指南: https://owasp.org/www-project-cheat-sheets/