Files
xuanzhi-service/server/.ai-specs/coding-specs/api-auth-control.md
wdh-home 8164eec650
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
服务端
2026-04-22 15:49:50 +08:00

5.7 KiB
Raw Permalink Blame History

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 层;禁止在 APIService 中靠 if token != ""if authorityId == ... 兜底模拟权限。
  • 修改接口鉴权时Swagger 注解必须同步:
    • 不需要登录:移除 @Security ApiKeyAuth
    • 需要登录:保留 @Security ApiKeyAuth
  • 业务路由统一在 router/<module> 调整;业务模块接入点统一在 initialize/router_biz.go 注册。

改成不需要登录

  • 把路由挂载从 PrivateGroup 或“仅登录组”移到 PublicRouter
  • 如果只是业务模块内部路由调整,不要改 APIService 方法签名。
  • 该接口如果不再作为后台角色权限点维护,必须把对应 path + method 从权限维护中移走,二选一即可:
    • 删除对应 sys_apis 记录。
    • 加入 sys_ignore_apis,避免后续 SyncApi 再次纳入权限页。
  • 若历史上已经给该接口分配过角色,必须同步清理对应 Casbin 规则,避免后台权限配置出现“看起来要授权、实际上公开可调”的假象。

改成需要登录,不需要权限

  • 当前项目没有全局现成的 LoginGroup;少量接口优先在对应 router 中基于 PublicRouter 单独挂 JWTAuth,不要为了一两个接口改全局入口。
  • 推荐写法:
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 还不够;CasbinHandlerpath + 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_apiscasbin_rule,却不改真实 router 挂载。
  • 禁止只把路由从 PublicGroup 挪到 PrivateGroup,却不补 sys_apis 和角色策略。
  • 禁止把“仅登录接口”偷懒挂到 PrivateGroup,再靠给所有角色放权来模拟“无权限限制”。
  • 禁止让公开接口长期保留在角色权限维护页里,造成权限含义失真。