前端加密请求 → coop-api 解密转发 → admanager-api → 加密响应返回前端
coop-api 是一个独立部署的 Go (Gin) 边界服务,承担以下职责:
admin_users 用户关联,复用 admanager 的角色与权限体系admanager-api 保持最小改动:不感知前端加密,不改变现有鉴权和业务逻辑,只增加两个内部接口与一张关联表。
| 链路 | 策略 |
|---|---|
| 前端 ↔ coop-api | 业务请求/响应全部密文,仅 /v1/pubkey 与健康检查明文 |
| coop-api ↔ admanager-api | 内网明文,已有 HTTPS/TLS,不落明文日志 |
| coop-api ↔ MySQL (coop_api) | 独立数据库,保存用户、会话、加密后的 admanager Token |
| admanager ↔ MySQL / Redis | 保持不变 |
| S3 文件存储 | 明文存储;上传/下载通道由 coop-api 做传输加密(后续实现) |
| 表 | 字段 | 说明 |
|---|---|---|
coop_users |
id, username, password_hash, nickname, status, admanager_user_id, created_at, updated_at |
coop 自建用户;admanager_user_id 为正向绑定字段 |
coop_sessions |
id, token_hash, user_id, admanager_token_encrypted, admanager_token_expires_at, expires_at, created_at |
会话;Token 存 SHA-256 哈希,admanager Token 用 AES-GCM 加密存储 |
| 表 | 字段 | 说明 |
|---|---|---|
tbl_admin_user_coop_users |
id, coop_user_id, admin_user_id, created_at, updated_at |
反向绑定关系;coop_user_id 与 admin_user_id 均唯一 |
admin_users 原表新增 coop_user_id 字段的方案,避免核心表结构膨胀,后续扩展多上游/多账号关系更灵活。
key_id 支持密钥轮换request_id + timestamp 用于防重放,默认允许 60 秒偏差POST /v1/relay
Content-Type: application/json
{
"version": 1,
"key_id": "dev-1",
"request_id": "uuid",
"timestamp": 1785900000,
"encrypted_key": "base64(RSA-OAEP(AES key))",
"nonce": "base64(nonce)",
"ciphertext": "base64(AES-GCM(内部请求))"
}
{
"method": "POST",
"path": "/api/ad_manage/insights",
"query": { "page": "1" },
"headers": { "Content-Type": "application/json" },
"body": { "date_start": "2026-08-01" },
"session_token": "coop 会话 Token"
}
{
"version": 1,
"key_id": "dev-1",
"request_id": "uuid",
"nonce": "base64(新 nonce)",
"ciphertext": "base64(AES-GCM(内部响应))"
}
{
"status": 200,
"headers": { "Content-Type": "application/json" },
"body": "base64(上游响应原文)"
}
GET /v1/pubkey
{
"key_id": "dev-1",
"public_key": "-----BEGIN PUBLIC KEY-----..."
}
| 接口 | 内部明文 | 返回 |
|---|---|---|
POST /v1/auth/register | {username, password, nickname} | 用户信息 |
POST /v1/auth/login | {username, password} | {token, user} |
POST /v1/auth/logout | {token} | {ok: true} |
POST /v1/auth/me | {token} | 用户信息 |
POST /v1/relay
内部请求中携带 session_token,coop-api 会解析出 admanager Token 并自动注入 Authorization: Bearer ...,前端无需接触 admanager Token。
| 外层 HTTP | 内部 status | 含义 |
|---|---|---|
| 400 | 400 | 信封非法 / 解密失败 / 参数错误 |
| 200 | 409 | 重复 request_id / 用户名冲突 |
| 200 | 401 | 会话无效 / 登录失败 |
| 200 | 404 | 上游路由未匹配 |
| 200 | 502 | 上游请求失败 |
两个接口仅限内网调用,均需请求头 X-Internal-Token,由 COOP_API_INTERNAL_TOKEN 配置校验。
POST /api/internal/coop-users
请求:
{
"coop_user_id": 1,
"username": "alice",
"name": "Alice"
}
响应:
{
"admin_user_id": 101
}
逻辑:先查 admin_user_coop_users,存在则直接返回;不存在则创建 admin_users 记录(无角色、无应用权限,需管理员后续授权)并写入关联表。
POST /api/internal/admin-session
请求:
{
"admin_user_id": 101
}
响应:
{
"token": "60位随机字符串"
}
逻辑:校验用户存在且启用,调用 AdminUserService::setToken 写入 Redis,有效期沿用现有 7 天。
X-Internal-Token: ${COOP_API_INTERNAL_TOKEN}
使用 hash_equals 做常量时间比较,避免时序攻击。
crypto:
key_id: dev-1
private_key_path: /path/to/server_private.pem
max_skew: 60s
relay:
max_request_bytes: 16777216
max_response_bytes: 16777216
upstream_timeout: 30s
replay_ttl: 60s
database:
driver: mysql
host: 127.0.0.1
port: 3306
name: coop_api
user: root
password: "" # 推荐从 .env 注入
auth:
session_ttl: 168h
admanager_internal_url: http://127.0.0.1:8000
admanager_internal_token: ${COOP_API_INTERNAL_TOKEN}
admanager_token_encryption_key: ${ADMANAGER_TOKEN_ENCRYPTION_KEY}
upstreams:
- name: admanager
path_prefix: /api
target: http://127.0.0.1:8000
strip_prefix: false
COOP_API_INTERNAL_TOKEN=一段随机的共享密钥
CRYPTO_PRIVATE_KEY_PATH 与 ADMANAGER_TOKEN_ENCRYPTION_KEY 必须配置固定值;当前留空会使用临时密钥,重启后会话无法解密。
cd /Users/chenxin/data/judian/admanager-api
php artisan migrate
新增表:tbl_admin_user_coop_users(实际表名随 DB 前缀自动生成)。
当前由服务启动时自动执行建表(coop_users / coop_sessions);后续正式环境建议引入独立迁移工具管理。
| 文件 | 职责 |
|---|---|
cmd/server/main.go | 入口、配置、信号处理 |
internal/config/ | YAML + .env 配置加载 |
internal/crypto/ | RSA-OAEP + AES-GCM 信封 |
internal/auth/ | 注册/登录/会话/绑定存储 |
internal/relay/ | 解密转发、防重放、会话注入 |
internal/server/ | Gin 路由、HTTP Server、优雅停机 |
| 文件 | 职责 |
|---|---|
routes/api.php | 注册两个内部路由 |
app/Http/Controllers/Internal/CoopUserController.php | 内部创建用户 / 签发会话 |
app/Http/Middleware/InternalTokenAuth.php | X-Internal-Token 校验 |
app/Models/Admin/AdminUserCoopUser.php | 关联表模型 |
database/migrations/2026_08_05_000000_create_admin_user_coop_users_table.php | 关联表迁移 |
config/services.php | COOP_API_INTERNAL_TOKEN 配置 |
cd /Users/chenxin/data/judian/coop-api
go test ./...
go vet ./...
php -l app/Http/Controllers/Internal/CoopUserController.php
php -l app/Http/Middleware/InternalTokenAuth.php
php artisan route:list --path=internal
php artisan migrate --pretend --path=database/migrations/2026_08_05_000000_create_admin_user_coop_users_table.php
GET /v1/pubkey 可获取 RSA 公钥session_token 时,上游能收到正确的 Bearer Tokenrequest_id 重复提交被拒绝X-Internal-Token 时返回 401php artisan migrate.env 配置 COOP_API_INTERNAL_TOKENcoop_api 数据库/v1/upload 分片加密上传,对接现有 /api/upload/chunk 与 /api/upload/makefile