应对管理员访问凭证失守导致的数据外泄风险,新增三层防护: 审计日志(admin-only 可见,用户不可见) - 新增 append-only audit_logs 表(migration 180)+ 异步批量写入 + 保留期清理 - 审计中间件挂在 admin/user/auth/admin-payment 组认证之后:记录所有变更类 请求 + 白名单敏感读取(账号/代理导出、备份下载、admin/user API key 读取) - 请求头凭证首尾掩码;请求体 JSON 递归脱敏(api_key/password 等擦除,base_url 保留以便追责);非 JSON body 不入库 - 无单条删除;全量清空需现场 TOTP 校验、拒绝 admin API key、未启用 2FA 不允许, 清空后同步写入留痕记录 会话 IP/UA 绑定(默认开启,可在系统设置关闭) - JWT 携带 session id + IP/UA 指纹哈希;IP 或 UA 任一变化即撤销会话家族并要求 重新登录;旧 token 无指纹时放行以平滑升级 敏感操作 step-up 2FA(sudo 窗口 15 分钟) - 账号/代理导出、DB 备份创建/下载、S3 目标修改要求近期 TOTP 二次验证;admin API key 一律拒绝;前端 useStepUp 组合式 + TotpStepUpDialog 弹码后自动重试 - API key 查看按需求暂不加强管控 前端:新增 /admin/audit-logs 操作日志页面(筛选/详情/2FA 清空)、侧边栏入口、 step-up 弹窗接入导出与备份流程、安全设置项(绑定开关 + 日志保留天数)、zh/en i18n
58 lines
1.4 KiB
Go
58 lines
1.4 KiB
Go
package main
|
|
|
|
import (
|
|
"context"
|
|
"flag"
|
|
"fmt"
|
|
"log"
|
|
"time"
|
|
|
|
_ "github.com/Wei-Shaw/sub2api/ent/runtime"
|
|
"github.com/Wei-Shaw/sub2api/internal/config"
|
|
"github.com/Wei-Shaw/sub2api/internal/repository"
|
|
"github.com/Wei-Shaw/sub2api/internal/service"
|
|
)
|
|
|
|
func main() {
|
|
email := flag.String("email", "", "Admin email to issue a JWT for (defaults to first active admin)")
|
|
flag.Parse()
|
|
|
|
cfg, err := config.LoadForBootstrap()
|
|
if err != nil {
|
|
log.Fatalf("failed to load config: %v", err)
|
|
}
|
|
|
|
client, sqlDB, err := repository.InitEnt(cfg)
|
|
if err != nil {
|
|
log.Fatalf("failed to init db: %v", err)
|
|
}
|
|
defer func() {
|
|
if err := client.Close(); err != nil {
|
|
log.Printf("failed to close db: %v", err)
|
|
}
|
|
}()
|
|
|
|
userRepo := repository.NewUserRepository(client, sqlDB)
|
|
authService := service.NewAuthService(client, userRepo, nil, nil, cfg, nil, nil, nil, nil, nil, nil, nil, nil)
|
|
|
|
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
|
|
defer cancel()
|
|
|
|
var user *service.User
|
|
if *email != "" {
|
|
user, err = userRepo.GetByEmail(ctx, *email)
|
|
} else {
|
|
user, err = userRepo.GetFirstAdmin(ctx)
|
|
}
|
|
if err != nil {
|
|
log.Fatalf("failed to resolve admin user: %v", err)
|
|
}
|
|
|
|
token, err := authService.GenerateToken(ctx, user)
|
|
if err != nil {
|
|
log.Fatalf("failed to generate token: %v", err)
|
|
}
|
|
|
|
fmt.Printf("ADMIN_EMAIL=%s\nADMIN_USER_ID=%d\nJWT=%s\n", user.Email, user.ID, token)
|
|
}
|