Skip to main content

zerx-security

zerxLabKit 认证与安全机制(JWT/会话/刷新/验证码/防爆破/审计日志/文件上传/对象存储)。当处理登录注册、token 刷新、会话管理、登录限流、操作日志、上传、存储 driver 时使用。Keywords: JWT, access token, refresh token, 会话, session, jti, 单点登录, AUTH_SINGLE_SESSION, 验证码, captcha, 防爆破, ratelimit, 锁定, 审计, 操作日志, OperationLog, login_logs, 上传, upload, 对象存储, storage, local, s3, minio, password policy, password reset, SMTP, mailer, TOTP, 2FA, MFA, export, import, xlsx, OpenAPI, docs, cron, job, scheduler, readyz, 安全, security, 认证, auth

Quellinformationen

Repository
zerx-lab/ZerxLabKit
Letzte Quellaktivität
24. Juni 2026 um 08:21
Erkannte Sprache von SKILL.md
Chinesisch
Sterne
0
Forks
0

Installationsoptionen

Standardmäßig ist der Prompt ausgewählt, der zuerst die Quelle prüft. Sie können zu einem direkten Befehl wechseln oder eine lokale Kopie herunterladen.

Quelldateien prüfen

Lesen Sie SKILL.md und alle von SkillsMP angezeigten Begleitdateien, bevor Sie sich für eine Installation entscheiden.

SKILL.md wird angezeigt

SKILL.md
Quellanweisungen · Schreibgeschützte Vorschau
name
zerx-security
description
zerxLabKit 认证与安全机制(JWT/会话/刷新/验证码/防爆破/审计日志/文件上传/对象存储)。当处理登录注册、token 刷新、会话管理、登录限流、操作日志、上传、存储 driver 时使用。Keywords: JWT, access token, refresh token, 会话, session, jti, 单点登录, AUTH_SINGLE_SESSION, 验证码, captcha, 防爆破, ratelimit, 锁定, 审计, 操作日志, OperationLog, login_logs, 上传, upload, 对象存储, storage, local, s3, minio, password policy, password reset, SMTP, mailer, TOTP, 2FA, MFA, export, import, xlsx, OpenAPI, docs, cron, job, scheduler, readyz, 安全, security, 认证, auth
# zerxLabKit 认证与安全机制 > Claude 已熟悉 JWT / RBAC / 限流概念;以下是 zerxLabKit 特有规则。授权裁决见 `skill://zerx-authz`。 ## JWT 与启动 - **生产必设 `JWT_SECRET`**:缺失则启动失败(`os.Exit(1)`)。 - **无默认账号**:不 seed 管理员;`/register`(public)首个注册者(库中用户数为 0 时)角色为 `admin`,其后为 `user`;邮箱唯一(冲突 → `CodeAlreadyExists`)。 - token 时效:access **15m**、refresh **168h**。`Claims{ UserID uint64, Roles []string, TokenType string }`(多角色);`Issuer.IssueAccess(userID uint64, roles []string)`、`IssueRefresh / ParseAccess / ParseRefresh`(`internal/auth/jwt.go`)。 - h2c(明文 HTTP/2)仅供 `grpcurl` 等工具;浏览器 SPA 走 HTTP/1.1,不依赖 h2c。 - 前端刷新:`transport.ts` 实现 401 → single-flight 刷新 → 重试一次 → 仍失败清 token 跳登录。 ## 会话(多点登录) - refresh 的 **jti = 会话 ID**,对应 `user_sessions` 行。 - `AUTH_SINGLE_SESSION=true`:每次登录在同一事务内删除该用户其它会话(单端);默认允许多端,「会话管理」页查看/下线。 - 撤销会话**即时阻断 refresh**;access 无状态,自然过期后(≤15m)彻底失效。即时强制下线需每请求查会话(默认不开)。 ## 密码策略(`internal/auth/policy.go`) - `NewPolicy(cfg.Password) *Policy`;`Validate(pw)`(长度 + 大小写/数字/符号开关)、`CheckHistory(ctx, db, userID, newPlain)`(拒绝最近 N 个旧密码)、`RecordHistory(ctx, db, userID, hash)`(写 `password_history`,超 N 裁剪)。 - 配置 `PasswordPolicyConfig{ MinLength, RequireUpper/Lower/Digit/Symbol, HistoryCount }`(默认 8 位、仅要求数字、保留 3 条历史)。 - 用户改密 / 重置 / 管理员建用户均经 `policy`(`AuthService.ChangePassword`、`UserService`)。 ## 密码重置(邮件,`internal/mailer`) - public RPC `AuthService.RequestPasswordReset` → 生成 `password_reset_tokens` 行,经 `mailer.Send(ctx, to, subject, htmlBody)` 发链接;`ConfirmPasswordReset` 校验 token + `policy` 设新密码。 - `NewMailer(cfg.SMTP, logger)`;`SMTP_ENABLED=false` 时邮件仅记日志(开发不阻塞流程)。 ## TOTP 二次验证(2FA) - selfServe RPC `SetupTotp`(出 secret/二维码)→ `ActivateTotp`(验码启用,落 `user_totp` + `totp_recovery_codes`,`User.TotpEnabled=true`)→ `DisableTotp`;管理员 `UserService.DisableUserTotp`。 - `Login` 入参加 `totp_code`;启用 2FA 的用户首轮无码登录返回 `LoginResponse.totp_required=true`。 ## 全局限流(`internal/ratelimit` + `NewRateLimitInterceptor`) - per-IP token-bucket(`NewLimiter(RPS, Burst, TTL)`);超限返 `CodeResourceExhausted`。 - 拦截器**置于 OperationLog 外层**:被拒请求不落库(避免高压 DB 放大)。`RateLimitConfig{ Enabled(默认 true), RPS=20, Burst=40, TTL=10m }`。 ## 验证码 / 登录防爆破(`internal/captcha`、`AuthService` 内 LoginGuard) - 按 `email|IP` 滑动窗口计数:达 `AUTH_CAPTCHA_THRESHOLD` 后登录需 base64 验证码;达 `AUTH_LOCK_THRESHOLD` 后临时锁定 `AUTH_LOCK_FOR`。 - 登录成功 / 失败均写 `login_logs`。 - 验证码内存 store(进程内)。 ## 审计 / 错误日志(`internal/server/audit_interceptor.go`) - `OperationLog` 的**唯一写入者**:记录所有写操作与失败请求,**永不记录 body**。 - 兼 panic 兜底(具名返回 + recover,替代 `connect.WithRecover`,把 panic 与栈写入同一行)。 - handler 可经 `audit.Record(ctx, detail)`(或 `audit.WithHolder` 取 holder)写 `OperationLog.Detail` 字段;拦截器落库时读 `holder.Detail`。 - 错误日志 = OperationLog 中 `status != "ok"` 的行,**无独立表**;LoginLog / ListOperationLogs / ListErrorLogs 支持 status/method/start_at/end_at 过滤。 ## 上传与对象存储(`internal/storage`、`internal/media`) - `/api/upload`(multipart):任意已登录用户可用;**20MB** 上限、扩展名白名单、uuid key 防碰撞;表单 `visibility` 字段(`public|authenticated|private`,非法值兜底 `private`)写入 `File.Visibility`。返回 `url` = `media.ResolveFile(key, visibility)`。 - 前端用 `transport.ts` 的 `authedFetch`(共享 401 刷新)。 - driver = `local`(磁盘)| `s3`(minio-go);`StorageConfig{Driver, LocalDir, LocalBaseURL, S3Endpoint, S3AccessKey, S3SecretKey, S3Bucket, S3Region, S3Secure, S3PublicURL, SignedURLTTL}`(`STORAGE_SIGNED_URL_TTL` 默认 `1h`;配置见 `.env.example`)。 - `Storage` 接口(`storage.go`):`Save` **不返回 url**(只 error);`PublicURL(key) string`(无 public base URL 时返 "")、`Open(ctx,key) (io.ReadSeekCloser, time.Time, error)`、`Presign(ctx,key,ttl) (string, error)`(local 返 "",nil)。URL 不再落库——`File` 存 `Key`+`Visibility`,展示时经 media 动态解析。 ### 文件可见性与媒体访问(`internal/media` + `internal/server/media.go`) - **三层可见性**(`model.Visibility{Public,Authenticated,Private}`,默认 `private`),区别于 Casbin **接口**鉴权——这是 **blob 内容**鉴权:`public` 任何人;`authenticated` 任意登录用户;`private` 仅 owner(`UploadedBy`)或 admin。`FileService.DeleteFile` 同样限 owner/admin(否则 `CodePermissionDenied`)。 - **签名 URL = capability token**:local 用 HMAC-SHA256(`sign(key,exp)` over `key\nexp`,base64url),签名密钥 `sha256(JWT.Secret + "/media-url-v1")`(`server.New` 构造,仅 local);s3 用原生预签名 GET(`store.Presign`)。`Verify` 常量时间比对 + 校验 `exp`。TTL:文件 `SignedURLTTL`、头像固定 `avatarTTL=24h`。 - `media.Media` 解析:`ResolveFile(key,vis)`(public→`PublicURL`,否则签名 URL)、`ResolveAvatar(stored)`(空/外链直通,否则签名 `avatarTTL`)、`ResolveLogo(stored)`(logo 恒 public)、`NormalizeStored(value)`(写侧把签名/旧 URL 归一为裸 key,幂等)、`Open(ctx,key)`。 - `server.go`:driver=local 时 `LocalBaseURL+"/"` 挂 **`mediaHandler`**(可见性鉴权,非裸 `http.FileServer`):`public` 直发(可缓存);protected 需有效签名(capability)**或** Bearer access token 满足可见性。`mediaResolver` 注入 `AuthService`/`UserService`/`FileService`/`uploadHandler`。 ## 导出 / 导入 / API 文档(非 connectRPC,裸 HTTP) - `/api/export/{users,operation-logs,login-logs,error-logs}`(xlsx)、`/api/import/users`、`/api/import/users/template`:**手写 JWT 认证 + Casbin 鉴权**(对应 List procedure,`exportHandler(issuer, enforcer, db)` 等),不走拦截器链。 - `DOCS_ENABLED=true`(默认)挂 `/api/openapi.yaml`(go:embed)+ `/api/docs`(Scalar);`gen/openapi/` 由 `task gen` 产出。 - `/readyz`:DB ping(2s 超时)就绪探针;`/healthz`:存活探针(恒 200)。 ## 定时任务(`internal/jobs`) - `jobs.New(db, registry, logger)` + `Start()` 调度 enabled 任务;`main.go` 装配并 `defer Shutdown()`。`NewRegistry(db)` 绑内置 handler(如 `log_cleanup`);`ValidCron` 校验 5 段标准 cron。`JobService` 管 `scheduled_jobs` / `job_executions`、`RunNow`。 ## 配置(`internal/config/config.go`) - `Config{ Server, DB, JWT, Auth, Storage, Password, SMTP, RateLimit, Env }`。 - `AuthConfig{ SingleSession, CaptchaThreshold, LockThreshold, LockFor }`;`ServerConfig{ Addr, DocsEnabled }`;新增 `PasswordPolicyConfig` / `SMTPConfig` / `RateLimitConfig`(见上各节,全量 env 见 `.env.example`)。 - `Load()`:非 prod 先 `godotenv.Load()`,再 `env.ParseAs[Config]()`。 ## 安全模型注意 - **进程内状态(单实例假设)**:LoginGuard、`param.Cache`、captcha store、Casbin 决策缓存均进程内,水平扩容不跨实例一致(本脚手架无 Redis,是有意取舍)。 - **IP 来源**:取 `req.Peer().Addr` 去端口;反向代理后会变代理 IP,生产经代理需自行接 `X-Forwarded-For`。 - **纯 Go / CGO-free**:构建 `CGO_ENABLED=0`;新增依赖须纯 Go。 ## 源码锚点 `internal/auth/{jwt.go,policy.go}`、`internal/{ratelimit,captcha,mailer,audit,jobs,storage,media}/`、`internal/server/{audit_interceptor.go,interceptors.go,export.go,import.go,docs.go,httpauth.go,upload.go,media.go,server.go}`、`internal/model/file.go`、`internal/config/config.go`、`web/src/lib/transport.ts`、`.env.example`。
Auf GitHub ansehen