Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
93 changes: 93 additions & 0 deletions smf-h/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
# AI Chat Service

一个包含用户认证、模型权限控制、会话持久化、历史缓存与 Swagger 文档的简化 AI 多轮对话示例服务。

## 功能特性
- 用户注册 / 登录(JWT,环境变量可覆盖密钥)
- 模型访问权限控制(用户等级 / 角色 + 模型最小等级)
- 会话与消息:MySQL 持久化 + 内存缓存 + 最近历史 Redis 缓存
- 统一错误码与结构化响应(支持多类错误 swagger 展示)
- Swagger 文档(动态生成)
- 环境变量安全覆写配置,真实 `config.yaml` 不提交
- Redis 可选:失败自动降级不影响主流程

## 快速启动 (Windows PowerShell)
```powershell
# 可选:克隆后进入目录
# git clone <your-fork-url> && cd awesomeProject

# 1. 准备示例配置(真实敏感值用环境变量覆盖)
Copy-Item config\config.example.yaml config\config.yaml

# 2. 设置必要环境变量(示例,可按需调整)
$env:MYSQL_PASSWORD = "your_mysql_password"
$env:AUTH_JWT_SECRET = "your_jwt_secret"
# 如果需要真实模型调用
# $env:ARK_API_KEY = "your_model_api_key"

# 3. 启动服务
go run main.go

# 4. 打开 Swagger
# http://localhost:8080/swagger/index.html
```

## 错误码对照(节选)
| code | 含义 |
|------|------|
| 0 | 成功 |
| 40001 | 参数错误 |
| 40002 | 模型不存在或未配置 |
| 40101 | 未认证 |
| 40301 | 模型权限不足 |
| 40302 | 会话归属错误 |
| 50000 | 内部错误 |
| 50001 | 模型返回为空 |

完整说明参见:`docs/api.md`

## 目录说明
```
internal/ 内部逻辑模块
auth/ JWT、密码哈希、中间件
config/ 配置加载与环境变量覆写
db/ 数据库初始化
memory/ 内存会话管理
models/ GORM 实体
redisstore/ Redis 可选缓存封装
config/ 配置文件目录(示例 + 本地实际)
docs/ 架构/接口/安全/代码说明文档
main.go 程序入口与路由
```

## 常见环境变量
```
MYSQL_HOST / MYSQL_PORT / MYSQL_USER / MYSQL_PASSWORD / MYSQL_DB / MYSQL_CHARSET
AUTH_JWT_SECRET / AUTH_ACCESS_TTL
CHAT_DEFAULT_MODEL / CHAT_MAX_HISTORY / CHAT_MEMORY_LIMIT_MSGS
REDIS_HOST / REDIS_PORT / REDIS_PASSWORD / REDIS_DB
```
详细列表:`docs/SECURITY_CONFIG.md`

## Redis 最近历史缓存
- Key: `chat:conv:recent:<conversation_id>`
- 写入:发送消息成功后
- 读取:历史接口优先命中;失败走 DB 回源
- 降级:Redis 初始化失败时自动忽略缓存

## 后续可扩展
- SSE 流式输出
- 速率限制 (Redis Incr)
- 会话列表接口
- 模型 Provider 抽象层

## PR / 评审建议
- 不要提交 `config/config.yaml`
- 通过 README 步骤可本地快速运行
- 安全策略见 `docs/SECURITY_CONFIG.md`

## License
按上游仓库策略或后续补充。

---
**END**
42 changes: 42 additions & 0 deletions smf-h/config/config.example.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
# 示例配置文件。提交 PR 时请使用本文件,真实敏感信息放在本地 config.yaml(已被 .gitignore 忽略)。
server:
port: 8080
mode: release
mysql:
host: 127.0.0.1
port: 3306
user: root
password: CHANGE_ME
database: ai_chat
charset: utf8mb4
chat:
default_model: doubao-seed-1-6-250615
max_history: 12
memory_limit_msgs: 200
request_timeout: 15s
auth:
jwt_secret: CHANGE_ME_JWT_SECRET
access_ttl: 24h
models:
- id: doubao-seed-1-6-250615
min_level: 1
- id: deepseek-v3-1-terminus
min_level: 3
- id: kimi-k2-250905
min_level: 5
redis:
host: 127.0.0.1
port: 6379
password: "" # 本地无密码
db: 0
pool_size: 20
dial_timeout: 2s
read_timeout: 1s
write_timeout: 1s

# 使用环境变量覆盖敏感值 (示例):
# setx MYSQL_PASSWORD "real_password"
# setx AUTH_JWT_SECRET "real_jwt_secret"
# setx REDIS_PASSWORD "redis_pwd"
# 或 PowerShell 当前会话:
# $env:MYSQL_PASSWORD="real_password"
35 changes: 35 additions & 0 deletions smf-h/config/config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
server:
port: 8080
mode: debug
mysql:
host: 127.0.0.1
port: 3306
user: root
password: 2823128231
database: ai_chat
charset: utf8mb4
chat:
default_model: doubao-seed-1-6-250615
max_history: 12
memory_limit_msgs: 200
request_timeout: 15s
auth:
jwt_secret: change_me_dev_secret
access_ttl: 24h
models:
- id: doubao-seed-1-6-250615
min_level: 1
- id: deepseek-v3-1-terminus
min_level: 3
- id: kimi-k2-250905
min_level: 5

redis:
host: 127.0.0.1
port: 6379
# password: 2823128231
db: 0
pool_size: 20
dial_timeout: 2s
read_timeout: 1s
write_timeout: 1s
Comment on lines +1 to +35
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

严重安全问题:敏感配置文件不应提交到代码库。

此文件包含真实的敏感信息:

  • 第 8 行:MySQL 密码 2823128231
  • 第 17 行:JWT 密钥(虽然标记为开发用,但不应提交)
  • 第 30 行:Redis 密码(虽被注释,仍然暴露)

根据 PR 目标和 README.md(第 86 行)的明确说明:"不要提交 config/config.yaml"。

必须立即采取的措施:

  1. 从此 PR 中移除 config/config.yaml 文件
  2. 将其添加到 .gitignore(如果尚未添加)
  3. 使用 config.example.yaml 作为模板,用户应在本地复制并填入真实值
  4. 如果已经提交到历史记录,考虑使用 git filter-branch 或 BFG Repo-Cleaner 清理历史
  5. 立即轮换所有已暴露的密钥和密码

参考 config/config.example.yaml 的正确做法:使用 CHANGE_ME 等占位符,并通过环境变量覆盖敏感值。

🤖 Prompt for AI Agents
In smf-h/config/config.yaml lines 1-35: this file contains real secrets (MySQL
password, JWT secret, commented Redis password) and must not be in the repo;
remove config/config.yaml from the PR and working tree, add config/config.yaml
to .gitignore (or ensure config/ is ignored), replace it in the repo with a
config/config.example.yaml containing non-sensitive placeholders like CHANGE_ME
and documented env-variable overrides, instruct users to copy the example to
config/config.yaml locally, rotate the exposed credentials immediately, and if
secrets were already committed to history, run a history scrub (BFG or
git-filter-branch) to remove them from the repo history.

83 changes: 83 additions & 0 deletions smf-h/docs/SECURITY_CONFIG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
# 配置与密钥安全指南

本指南说明如何在提交代码(PR)时避免泄露敏感信息,并保证不同环境(本地/测试/生产)配置隔离。

## 1. 不要提交的内容
- 真实 `config/config.yaml` (已加入 .gitignore)
- 数据库密码、JWT 密钥、第三方 API Key (如 ARK_API_KEY)
- 生产 Redis / MySQL 地址
- 私有证书、密钥对、令牌文件

## 2. 提交什么
| 文件 | 作用 | 是否包含敏感信息 |
|------|------|------------------|
| `config/config.example.yaml` | 示例/模板 | 否(占位符) |
| `internal/config/config.go` | 解析 + 环境变量覆盖 | 否 |
| `.gitignore` | 忽略真实配置 | 否 |

## 3. 本地真实配置放哪里
- 开发: `config/config.yaml` (不会被 git 追踪)
- 生产: 推荐使用环境变量 + 仅最小必要的 fallback config 文件

## 4. 环境变量覆盖支持 (已实现)
支持的变量 (非空即覆盖):
```
SERVER_PORT, SERVER_MODE
MYSQL_HOST, MYSQL_PORT, MYSQL_USER, MYSQL_PASSWORD, MYSQL_DB, MYSQL_CHARSET
AUTH_JWT_SECRET, AUTH_ACCESS_TTL
CHAT_DEFAULT_MODEL, CHAT_MAX_HISTORY, CHAT_MEMORY_LIMIT_MSGS, CHAT_REQUEST_TIMEOUT
REDIS_HOST, REDIS_PORT, REDIS_PASSWORD, REDIS_DB, REDIS_POOL_SIZE,
REDIS_DIAL_TIMEOUT, REDIS_READ_TIMEOUT, REDIS_WRITE_TIMEOUT
```
示例 (PowerShell 临时会话):
```powershell
$env:MYSQL_PASSWORD = "SuperSecret!"
$env:AUTH_JWT_SECRET = "ProdJwtSecret_ChangeMe"
$env:REDIS_PASSWORD = "RedisPwd123"
```

## 5. PR 前自检清单
| 检查项 | 通过条件 |
|--------|----------|
| config.yaml 是否未被提交 | `git status` 无该文件 |
| 未把真实密码硬编码进代码 | 搜索 `password:` / `jwt_secret:` 无真实值 |
| 关键密钥均可用 env 注入 | 启动服务时通过日志/调试确认被覆盖 |

## 6. CI/CD 建议
- 使用平台 Secret 管理 (GitHub Actions Secrets / GitLab CI Variables)
- 部署启动脚本导出变量后再 `go run / build`:
```bash
export MYSQL_PASSWORD=$SECRET_MYSQL_PASSWORD
export AUTH_JWT_SECRET=$SECRET_JWT
./app
```
- 避免将密钥写入镜像层:用运行时注入 (Kubernetes Secret / Docker --env-file)

## 7. 生产加固建议
| 领域 | 建议 |
|------|------|
| JWT | 定期轮换密钥,考虑多个版本(旧+新)并行过渡 |
| 数据库 | 最小权限账号,禁止 *.* 全权限;开启 TLS (如需) |
| Redis | 绑定内网地址,启用 ACL 或至少强密码,禁止公网暴露 |
| 日志 | 不打印 token / 密码 / 完整 SQL (参数可脱敏) |
| 代码 | 通过 secret 扫描工具 (trufflehog / gitleaks) 预防泄露 |

## 8. 临时调试不泄露技巧
- 打印配置时跳过敏感字段 (`****`)。
- 将敏感值长度或 hash 输出用于核对是否加载到了正确的 Secret。

## 9. 应急处理
| 场景 | 动作 |
|------|------|
| 不小心提交密钥 | 立即在平台侧作废该密钥;强制推送清理历史(必要时);生成新 Key |
| 密钥疑似泄露 | 强制失效 + 全局通知 + 轮换;审计访问日志 |
| 配置被恶意篡改 | 使用只读挂载或配置签名校验 |

## 10. 后续可增强
- 引入 `.env` + dotenv 解析(本项目目前依赖系统 env)
- 加入启动时敏感配置缺失校验并统一错误提示
- 敏感值自动检测 pre-commit 钩子
- 支持 Vault / Secrets Manager 远程加载

---
**END**
Loading