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
5.7 KiB
5.7 KiB
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,不要为了一两个接口改全局入口。 - 推荐写法:
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_apisPOST <router-prefix>/api/enterSyncApi:确认把新增路由写入sys_apisPOST <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,再靠给所有角色放权来模拟“无权限限制”。 - 禁止让公开接口长期保留在角色权限维护页里,造成权限含义失真。