# 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/` 调整;业务模块接入点统一在 `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 策略缓存。 - 系统现成接口的完整路径 = `/api/...`;如果 `router-prefix` 为空,则完整路径就是 `/api/...`。不要把是否存在额外前缀写死成项目事实。 - 常用管理接口: - `GET /api/syncApi`:对比内存路由和 `sys_apis` - `POST /api/enterSyncApi`:确认把新增路由写入 `sys_apis` - `POST /api/setApiRoles`:全量覆盖某个接口的角色列表 - `GET /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`,再靠给所有角色放权来模拟“无权限限制”。 - 禁止让公开接口长期保留在角色权限维护页里,造成权限含义失真。