初步实现数据加密、权限管理、日志审计等功能

This commit is contained in:
2026-02-02 10:09:28 +08:00
parent b6b37a453b
commit 807e634318
27 changed files with 3787 additions and 59 deletions

391
DEPLOYMENT.md Normal file
View File

@@ -0,0 +1,391 @@
# 部署和集成指南
本文档说明如何将新的安全功能集成到现有系统中。
## 📦 已完成的功能
### 1. 数据加密模块
-`app/core/encryption.py` - Fernet 对称加密实现
- ✅ 支持敏感数据加密/解密
- ✅ 密钥管理和生成工具
### 2. 用户认证系统
-`app/domain/models/role.py` - 用户角色枚举 (ADMIN/OPERATOR/USER/VIEWER)
-`app/domain/schemas/user.py` - 用户数据模型和验证
-`app/infra/repositories/user_repository.py` - 用户数据访问层
-`app/api/v1/endpoints/auth.py` - 注册/登录/刷新Token接口
-`app/auth/dependencies.py` - 认证依赖项
-`migrations/001_create_users_table.sql` - 用户表迁移脚本
### 3. 权限控制系统
-`app/auth/permissions.py` - RBAC 权限控制装饰器
-`app/api/v1/endpoints/user_management.py` - 用户管理接口示例
- ✅ 支持基于角色的访问控制
- ✅ 支持资源所有者检查
### 4. 审计日志系统
-`app/core/audit.py` - 审计日志核心功能
-`app/domain/schemas/audit.py` - 审计日志数据模型
-`app/infra/repositories/audit_repository.py` - 审计日志数据访问层
-`app/api/v1/endpoints/audit.py` - 审计日志查询接口
-`app/infra/audit/middleware.py` - 自动审计中间件
-`migrations/002_create_audit_logs_table.sql` - 审计日志表迁移脚本
### 5. 文档和测试
-`SECURITY_README.md` - 完整的使用文档
-`.env.example` - 环境变量配置模板
-`tests/test_encryption.py` - 加密功能测试
---
## 🔧 集成步骤
### 步骤 1: 环境配置
1. 复制环境变量模板:
```bash
cp .env.example .env
```
2. 生成密钥并填写 `.env`
```bash
# JWT 密钥
openssl rand -hex 32
# 加密密钥
python -c "from cryptography.fernet import Fernet; print(Fernet.generate_key().decode())"
```
3. 编辑 `.env` 填写所有必需的配置项。
### 步骤 2: 数据库迁移
执行数据库迁移脚本:
```bash
# 方法 1: 使用 psql 命令
psql -U postgres -d tjwater -f migrations/001_create_users_table.sql
psql -U postgres -d tjwater -f migrations/002_create_audit_logs_table.sql
# 方法 2: 在 psql 交互界面
psql -U postgres -d tjwater
\i migrations/001_create_users_table.sql
\i migrations/002_create_audit_logs_table.sql
```
验证表已创建:
```sql
-- 检查用户表
SELECT * FROM users;
-- 检查审计日志表
SELECT * FROM audit_logs;
```
### 步骤 3: 更新 main.py
`app/main.py` 中集成新功能:
```python
from fastapi import FastAPI
from app.core.config import settings
from app.infra.audit.middleware import AuditMiddleware
app = FastAPI(title=settings.PROJECT_NAME)
# 1. 添加审计中间件(可选)
app.add_middleware(AuditMiddleware)
# 2. 注册路由
from app.api.v1.endpoints import auth, user_management, audit
app.include_router(
auth.router,
prefix=f"{settings.API_V1_STR}/auth",
tags=["认证"]
)
app.include_router(
user_management.router,
prefix=f"{settings.API_V1_STR}/users",
tags=["用户管理"]
)
app.include_router(
audit.router,
prefix=f"{settings.API_V1_STR}/audit",
tags=["审计日志"]
)
# 3. 确保数据库在启动时初始化
@app.on_event("startup")
async def startup_event():
# 初始化数据库连接池
from app.infra.db.postgresql.database import Database
global db
db = Database()
db.init_pool()
await db.open()
@app.on_event("shutdown")
async def shutdown_event():
# 关闭数据库连接
await db.close()
```
### 步骤 4: 保护现有接口
#### 方法 1: 为路由添加全局依赖
```python
from app.auth.dependencies import get_current_active_user
# 为整个路由器添加认证
router = APIRouter(dependencies=[Depends(get_current_active_user)])
```
#### 方法 2: 为单个端点添加依赖
```python
from app.auth.permissions import require_role, get_current_admin
from app.domain.models.role import UserRole
@router.get("/data")
async def get_data(
current_user = Depends(require_role(UserRole.USER))
):
"""需要 USER 及以上角色"""
return {"data": "protected"}
@router.delete("/data/{id}")
async def delete_data(
id: int,
current_user = Depends(get_current_admin)
):
"""仅管理员可访问"""
return {"message": "deleted"}
```
### 步骤 5: 添加审计日志
#### 自动审计(推荐)
使用中间件自动记录(已在 main.py 中添加):
```python
app.add_middleware(AuditMiddleware)
```
#### 手动审计
在关键业务逻辑中手动记录:
```python
from app.core.audit import log_audit_event, AuditAction
@router.post("/important-action")
async def important_action(
data: dict,
request: Request,
current_user = Depends(get_current_active_user)
):
# 执行业务逻辑
result = do_something(data)
# 记录审计日志
await log_audit_event(
action=AuditAction.UPDATE,
user_id=current_user.id,
username=current_user.username,
resource_type="important_resource",
resource_id=str(result.id),
ip_address=request.client.host,
request_data=data
)
return result
```
### 步骤 6: 更新 auth/dependencies.py
确保 `get_db()` 函数正确获取数据库实例:
```python
async def get_db() -> Database:
"""获取数据库实例"""
# 方法 1: 从 main.py 导入
from app.main import db
return db
# 方法 2: 从 FastAPI app.state 获取
# from fastapi import Request
# def get_db_from_request(request: Request):
# return request.app.state.db
```
---
## 🧪 测试
### 1. 测试加密功能
```bash
python tests/test_encryption.py
```
### 2. 测试 API
启动服务器:
```bash
uvicorn app.main:app --reload
```
访问交互式文档:
- Swagger UI: http://localhost:8000/docs
- ReDoc: http://localhost:8000/redoc
### 3. 测试登录
```bash
curl -X POST "http://localhost:8000/api/v1/auth/login" \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "username=admin&password=admin123"
```
### 4. 测试受保护接口
```bash
TOKEN="your-access-token"
curl -X GET "http://localhost:8000/api/v1/auth/me" \
-H "Authorization: Bearer $TOKEN"
```
---
## 🔄 迁移现有接口
### 原有硬编码认证
**旧代码** (`app/api/v1/endpoints/auth.py`):
```python
AUTH_TOKEN = "567e33c876a2"
async def verify_token(authorization: str = Header()):
token = authorization.split(" ")[1]
if token != AUTH_TOKEN:
raise HTTPException(status_code=403)
```
**新代码** (已更新):
```python
from app.auth.dependencies import get_current_active_user
@router.get("/protected")
async def protected_route(
current_user = Depends(get_current_active_user)
):
return {"user": current_user.username}
```
### 更新其他端点
搜索项目中使用旧认证的地方:
```bash
grep -r "AUTH_TOKEN" app/
grep -r "verify_token" app/
```
替换为新的依赖注入系统。
---
## 📋 检查清单
部署前检查:
- [ ] 环境变量已配置(`.env`
- [ ] 数据库迁移已执行
- [ ] 默认管理员账号可登录
- [ ] JWT Token 可正常生成和验证
- [ ] 权限控制正常工作
- [ ] 审计日志正常记录
- [ ] 加密功能测试通过
- [ ] API 文档可访问
---
## ⚠️ 注意事项
### 1. 向后兼容性
保留了简化版登录接口 `/auth/login/simple` 以兼容旧客户端:
```python
@router.post("/login/simple")
async def login_simple(username: str, password: str):
# 验证并返回 Token
...
```
### 2. 数据库连接
确保在 `app/auth/dependencies.py``get_db()` 函数能正确获取数据库实例。
### 3. 密钥安全
- ❌ 不要提交 `.env` 文件到版本控制
- ✅ 在生产环境使用环境变量或密钥管理服务
- ✅ 定期轮换 JWT 密钥
### 4. 性能考虑
- 审计中间件会增加每个请求的处理时间(约 5-10ms
- 对高频接口可考虑异步记录审计日志
- 定期清理或归档旧的审计日志
---
## 🐛 故障排查
### 问题 1: 导入错误
```
ImportError: cannot import name 'db' from 'app.main'
```
**解决**: 确保在 `app/main.py` 中定义了全局 `db` 对象。
### 问题 2: 认证失败
```
401 Unauthorized: Could not validate credentials
```
**检查**:
1. Token 是否正确设置在 `Authorization: Bearer {token}` header
2. Token 是否过期
3. SECRET_KEY 是否配置正确
### 问题 3: 数据库连接失败
```
psycopg.OperationalError: connection failed
```
**检查**:
1. PostgreSQL 是否运行
2. `.env` 中数据库配置是否正确
3. 数据库是否存在
---
## 📞 技术支持
详细文档请参考:
- `SECURITY_README.md` - 安全功能使用指南
- `migrations/` - 数据库迁移脚本
- `app/domain/schemas/` - 数据模型定义