Files
sundynix-pets/pets-be/README.md
T
Blizzard 9adafb1354 feat(auth): access token 缩到 2 小时 + refresh token 机制
后台登录框原来预填了 sundynix/sundynix,等于把凭证写在页面上,去掉。

令牌改为 access(2h) + refresh 两段式:
- 新表 sundynix_refresh_tokens,只存 sha256,明文只在签发时返回一次
- 有效期:小程序 30 天、后台 7 天
- 新接口 /api/auth/refresh|logout、/api/admin/refresh|logout

安全约定:
- 每次续期都轮换刷新令牌,旧的立即作废
- 作废后 60 秒内再到达算并发重试放行,超过则判定泄露、吊销该账号全部会话
- 主动退出与被连坐吊销的令牌不吃宽限期,否则「吊销全部」形同虚设
- 禁用用户时一并吊销刷新令牌,最多 2 小时彻底失去访问

两端请求层都做了单飞续期:并发请求同时 401 只发一次 refresh,
否则刷新令牌会被并发轮换掉互相打架。小程序续期失败回退 wx.login,
登录/续期请求标 noAuthRetry,避免登录失败(同样返回 40100)触发自我套娃。

顺带修掉 vite 代理仍指向 8080 的遗留(端口早已改 9090)。

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-29 09:38:19 +08:00

65 lines
3.5 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 毛孩子计划 · 后端 (pets-be)
Gin + GORM + MySQL + MinIO 的宠物小程序后端,内嵌 React(Vite + Tailwind + shadcn/ui) 后台管理。
## 技术栈与约定
- 模块路径 `github.com/sundynix/pets-be`,标准 Go 布局(`cmd/ internal/ pkg/ configs/ deployments/ web/`
- 所有数据库表带前缀 `sundynix_`
- 统一响应 `{code, message, data}``pkg/response`),列表接口统一分页参数 `page` / `page_size``response.PageQuery` + `PageResult`
- MySQL `root/root``pets`MinIO `sundynix/sundynix``pets`
- 服务端口 `:8080`;后台在 `http://localhost:8080/admin`seed 管理员 `sundynix/sundynix`
## 快速开始
```bash
# 1. 起依赖(MySQL + MinIO
make env-up # 或 cd deployments && docker compose up -d
# 2. 构建后台前端 + 后端单二进制
make build # 产物 bin/pets-be(已 embed 后台)
./bin/pets-be
# 或开发期直接运行(使用现有 internal/admin/dist
make run
```
### 后台前端开发(热更新)
```bash
make admin-dev # vite dev server :5173,已代理 /api → :8080
# 改完执行 make admin-build 让产物落到 internal/admin/dist,再 go build 即 embed
```
## 目录
- `cmd/server` 入口:载配置→连库→迁移→seed→建桶→路由→启动
- `internal/config` 配置(viper,支持 `PETS_` 环境变量覆盖)
- `internal/model` GORM 模型(`sundynix_` 前缀)
- `internal/database` 连接/迁移/seed
- `internal/storage` MinIO 封装(自动建桶 + 上传)
- `internal/service` 业务逻辑;`internal/handler` HTTP 处理器;`internal/router` 路由
- `internal/middleware` CORS / 用户鉴权 / 管理员鉴权
- `internal/admin` `go:embed` 内嵌后台产物 + SPA fallback
- `pkg/response` 统一响应与分页;`pkg/jwt` 令牌;`pkg/errcode` 错误码
- `web/admin` 后台前端源码
## 接口
- 小程序 `/api/*`(用户 JWT):auth / user / pets / onboarding / records / tasks / plan / reminders / report / bill / community / articles / pro / ai / upload
- 后台 `/api/admin/*`(管理员 JWT):login / stats / users / pets / posts / comments / articles / memberships
## 登录鉴权
默认 `auth.dev_login: true``POST /api/auth/login {"nickname":"xxx"}` 即发用户 JWT。
接真微信:在 `configs/config.yaml``wechat.app_secret` 并把 `dev_login` 置 false,实现 `/api/auth/wechat`(code2session)。
### access token + refresh token
登录接口返回 `token`(access) 与 `refresh_token` 两个令牌:
- **access token**JWT,默认 **2 小时**`jwt.expire_hours`),放 `Authorization: Bearer`,服务端无状态校验。
- **refresh token**:随机串,落库 `sundynix_refresh_tokens`**只存 sha256**)。小程序 30 天、后台 7 天。
- 续期:`POST /api/auth/refresh` / `POST /api/admin/refresh`,入参 `{"refresh_token":"..."}`,返回新的一对令牌。
- 退出:`POST /api/auth/logout` / `POST /api/admin/logout` 作废该刷新令牌。
安全约定:
- **每次续期都轮换**刷新令牌,旧的立即作废;作废后 60 秒内再到达算并发重试(放行),超过则判定泄露,**吊销该账号全部会话**。
- 主动退出、被连坐吊销的令牌不享受宽限期。
- 禁用用户时一并吊销其刷新令牌,最多 2 小时后彻底失去访问。
前端两端都做了单飞续期:并发请求同时 401 只会发一次 refresh(否则刷新令牌会被并发轮换掉)。小程序续期失败会回退到 `wx.login` 重新登录。