服务端
Some checks failed
CI / init (push) Has been cancelled
CI / Frontend node 18.16.0 (push) Has been cancelled
CI / Backend go (1.22) (push) Has been cancelled
CI / devops-test (1.22, 18.16.0) (push) Has been cancelled
CI / release-pr (push) Has been cancelled
CI / release-please (push) Has been cancelled
CI / devops-prod (1.22, 18.x) (push) Has been cancelled
CI / docker (push) Has been cancelled
Some checks failed
CI / init (push) Has been cancelled
CI / Frontend node 18.16.0 (push) Has been cancelled
CI / Backend go (1.22) (push) Has been cancelled
CI / devops-test (1.22, 18.16.0) (push) Has been cancelled
CI / release-pr (push) Has been cancelled
CI / release-please (push) Has been cancelled
CI / devops-prod (1.22, 18.x) (push) Has been cancelled
CI / docker (push) Has been cancelled
This commit is contained in:
96
server/.ai-specs/coding-specs/api-auth-control.md
Normal file
96
server/.ai-specs/coding-specs/api-auth-control.md
Normal file
@@ -0,0 +1,96 @@
|
||||
# API 鉴权与权限修改规范
|
||||
|
||||
## 适用范围
|
||||
|
||||
- 新增接口时,需要判定它是“公开访问”“仅登录可访问”还是“登录且有权限才可访问”时,使用本文。
|
||||
- 已有接口在“不需要登录 / 需要登录 / 需要权限”之间切换时,使用本文。
|
||||
|
||||
## 现有鉴权基线
|
||||
|
||||
- `initialize/router.go` 当前只创建两类顶层路由组:
|
||||
- `PublicGroup`:不挂鉴权中间件。
|
||||
- `PrivateGroup`:统一挂 `middleware.JWTAuth()` 和 `middleware.CasbinHandler()`。
|
||||
- `JWTAuth` 定义在 `middleware/jwt.go`。
|
||||
- `CasbinHandler` 定义在 `middleware/casbin_rbac.go`。
|
||||
- 结论:
|
||||
- 挂到 `PublicGroup` = 不需要登录。
|
||||
- 挂到 `PrivateGroup` = 需要登录,且需要角色权限。
|
||||
- 当前仓库没有默认内置的“只登录、不校验权限”公共组。
|
||||
- 不存在“只校验权限、不登录”的合法模式;`CasbinHandler` 依赖 `JWTAuth` 写入的用户 claims。
|
||||
|
||||
## 权限模式判定
|
||||
|
||||
| 模式 | 路由挂载方式 | JWT | Casbin | 后续要求 |
|
||||
|:---|:---|:---|:---|:---|
|
||||
| 不需要登录 | `PublicGroup` / `PublicRouter` | 否 | 否 | 默认不作为角色权限点长期维护 |
|
||||
| 需要登录,不需要权限 | 基于 `PublicRouter` 单独加 `middleware.JWTAuth()` | 是 | 否 | 默认不进入角色权限维护 |
|
||||
| 需要登录且需要权限 | `PrivateGroup` / `Router` | 是 | 是 | 必须进入 `sys_apis` 并分配角色 |
|
||||
|
||||
## 强制规则
|
||||
|
||||
- 同一个 `path + method` 只能落一种鉴权模式;禁止同时注册到公开组和鉴权组。
|
||||
- `middleware.OperationRecord()` 只负责操作审计,不改变登录与权限判定。
|
||||
- 鉴权逻辑统一落在 `router` 层;禁止在 `API` 或 `Service` 中靠 `if token != ""`、`if authorityId == ...` 兜底模拟权限。
|
||||
- 修改接口鉴权时,Swagger 注解必须同步:
|
||||
- 不需要登录:移除 `@Security ApiKeyAuth`
|
||||
- 需要登录:保留 `@Security ApiKeyAuth`
|
||||
- 业务路由统一在 `router/<module>` 调整;业务模块接入点统一在 `initialize/router_biz.go` 注册。
|
||||
|
||||
## 改成不需要登录
|
||||
|
||||
- 把路由挂载从 `PrivateGroup` 或“仅登录组”移到 `PublicRouter`。
|
||||
- 如果只是业务模块内部路由调整,不要改 `API`、`Service` 方法签名。
|
||||
- 该接口如果不再作为后台角色权限点维护,必须把对应 `path + method` 从权限维护中移走,二选一即可:
|
||||
- 删除对应 `sys_apis` 记录。
|
||||
- 加入 `sys_ignore_apis`,避免后续 `SyncApi` 再次纳入权限页。
|
||||
- 若历史上已经给该接口分配过角色,必须同步清理对应 Casbin 规则,避免后台权限配置出现“看起来要授权、实际上公开可调”的假象。
|
||||
|
||||
## 改成需要登录,不需要权限
|
||||
|
||||
- 当前项目没有全局现成的 `LoginGroup`;少量接口优先在对应 router 中基于 `PublicRouter` 单独挂 `JWTAuth`,不要为了一两个接口改全局入口。
|
||||
- 推荐写法:
|
||||
|
||||
```go
|
||||
func (r *BookRouter) InitBookRouter(Router *gin.RouterGroup, PublicRouter *gin.RouterGroup) {
|
||||
bookLoginRouter := PublicRouter.Group("book").Use(middleware.JWTAuth())
|
||||
{
|
||||
bookLoginRouter.GET("profile", bookApi.GetProfile)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
- 同一模块里如果“仅登录接口”很多,再考虑在 `initialize/router.go` 新增单独的 `LoginGroup`,并把它显式传入对应 router 初始化函数。
|
||||
- 这类接口禁止挂 `middleware.CasbinHandler()`。
|
||||
- 这类接口默认不进入 `sys_apis` 的角色权限维护;如果历史上已经进入,必须删除或加入 `sys_ignore_apis`,不要继续让后台把它当作“需要分配角色”的接口。
|
||||
|
||||
## 改成需要登录且需要权限
|
||||
|
||||
- 把路由挂到 `PrivateGroup` 或业务 router 的 `Router` 参数上。
|
||||
- 只把路由挪进 `PrivateGroup` 还不够;`CasbinHandler` 按 `path + method` 校验权限,没有角色策略就会直接返回“权限不足”。
|
||||
- 因此必须同时完成以下动作:
|
||||
- 确保该 `path + method` 存在于 `sys_apis`。
|
||||
- 确保该接口已分配允许访问的角色。
|
||||
- 刷新 Casbin 策略缓存。
|
||||
- 系统现成接口的完整路径 = `<router-prefix>/api/...`;如果 `router-prefix` 为空,则完整路径就是 `/api/...`。不要把是否存在额外前缀写死成项目事实。
|
||||
- 常用管理接口:
|
||||
- `GET <router-prefix>/api/syncApi`:对比内存路由和 `sys_apis`
|
||||
- `POST <router-prefix>/api/enterSyncApi`:确认把新增路由写入 `sys_apis`
|
||||
- `POST <router-prefix>/api/setApiRoles`:全量覆盖某个接口的角色列表
|
||||
- `GET <router-prefix>/api/freshCasbin`:刷新 Casbin 策略缓存
|
||||
- 若接口此前在 `sys_ignore_apis` 中,改成“需要权限”前必须先取消 ignore,再同步到 `sys_apis`。
|
||||
- 若不给任何角色分配该接口,则结果不是“仅登录可访问”,而是“所有已登录用户都权限不足”。
|
||||
|
||||
## 验证要求
|
||||
|
||||
- 修改完成后,至少验证下面三类请求结果:
|
||||
- 公开接口:不带 token 可访问成功。
|
||||
- 仅登录接口:不带 token 返回未登录;带有效 token 可访问成功。
|
||||
- 权限接口:不带 token 返回未登录;带无权角色 token 返回“权限不足”;带有权角色 token 可访问成功。
|
||||
- 如果改了接口鉴权方式,同时该接口出现在 Swagger、前端权限配置页、角色配置页,也必须同步核对展示结果是否一致。
|
||||
|
||||
## 禁止事项
|
||||
|
||||
- 禁止只改 `sys_apis` 或 `casbin_rule`,却不改真实 router 挂载。
|
||||
- 禁止只把路由从 `PublicGroup` 挪到 `PrivateGroup`,却不补 `sys_apis` 和角色策略。
|
||||
- 禁止把“仅登录接口”偷懒挂到 `PrivateGroup`,再靠给所有角色放权来模拟“无权限限制”。
|
||||
- 禁止让公开接口长期保留在角色权限维护页里,造成权限含义失真。
|
||||
Reference in New Issue
Block a user