

新闻资讯
技术学院Go项目初期选RBAC即可,结构清晰易实现;ABAC仅在需动态条件(如部门匹配)时引入。权限校验须前置中间件,缓存权限至context或Redis,权限字符串统一用resource:action格式。
大多数 Go 项目初期用 RBAC(基于角色的访问控制)就够了,它结构清晰、易实现、数据库建模简单。ABAC 虽灵活,但规则分散、调试困难,除非你明确需要「用户部门 == 当前资源所属部门」这类动态条件,否则别过早引入。
Go 里不用硬套框架,直接用结构体 + 映射就能跑通 RBAC 核心链路:
Role 表存角色名(如 "admin"、"editor")Permission 表存权限标识(如 "user:read"、"post:delete")role_permissions 关联表做多对多绑定user_role 得到角色 ID,再 JOIN 查对应所有 permission_code
权限检查必须前置,且失败要立即中断请求。推荐用 Gin 或 Echo 的中间件模式,在路由进入业务逻辑前完成校验。
关键点:
context 提取当前用户(通常来自 JWT 解析或 session),不是从 query/body 里临时读bool, error,error 用于区分「无权限」和「系统错误」——前者返回 403,后者返回 500
context.Value 或提前加载进 user struct 字段里func AuthMiddleware(requiredPerm string) gin.HandlerFunc {
return func(c *gin.Co
ntext) {
user, ok := c.Get("user").(*User)
if !ok {
c.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{"error": "no user in context"})
return
}
if !user.HasPermission(requiredPerm) { // 内存中查 map[string]bool
c.AbortWithStatusJSON(http.StatusForbidden, gin.H{"error": "insufficient permissions"})
return
}
c.Next()
}
}
权限标识建议统一用 resource:action 格式,例如 "order:create"、"report:export"。这种结构天然支持前缀匹配(比如 "order:*" 表示订单全部操作),也方便前端按模块过滤按钮。
避坑提示:
order_create —— 无法语义化分组,正则难写/api/v1/orders —— 把路径耦合进权限,REST 变更就崩"order" —— 后期没法细化读/写/删"User:Read" 和 "user:read" 被当成两个权限用户登录后,一次性查出所有权限并缓存在内存,比每次接口都 JOIN role_permissions 快得多,也避免 N+1 查询。
实操建议:
LoadUserPermissions(userID),返回 map[string]bool(key 是 "post:delete")userID:permissions 作 key,过期时间设为 24h,比 session 长一点,避免频繁重载invalidatePermissionCache(userID) 主动删 Redis keyPreload 在每次请求时懒加载权限——它会触发额外 SQL,且难以控制缓存粒度最常被忽略的是权限变更后的缓存一致性。上线后如果发现改了角色但接口还是 403,第一反应不是代码逻辑错,而是 Redis 里那条 permission 缓存还没过期。