权限校验必须用中间件统一拦截,禁止在handler中重复编写;中间件只负责取用户、查缓存/DB加载权限码,不拼SQL、不行级过滤;权限数据须数据库+Redis双层存储,支持热更新与审计。

权限校验别写在 handler 里,必须用中间件统一拦截
你不会想在每个 GET /users、POST /orders 里都重复写一遍 if !u.HasPermission("user:read")——这会导致逻辑分散、漏判、改权限要翻十几文件。Gin 的中间件天然适合做这件事,但很多人误以为“加个 AuthMiddleware() 就完事”,结果发现角色变了权限不更新、多实例缓存不同步。
- 中间件应只做一件事:从 context 取用户、查缓存(如
user:<id>:permissions</id>)、没命中再查 DB 并回填 Redis - 不要传角色名(如
"admin")进中间件,而要传权限码(如"order:delete"),因为 RBAC 的本质是「权限归属角色」,不是「角色决定一切」 - 避免在中间件里拼 SQL 或查具体数据——它不知道当前请求要删哪个订单,行级过滤必须下放到业务 handler
权限数据不能硬编码,必须走数据库+缓存双层存储
把权限列表写成 map[string][]string{"admin": {"user:read", "user:write"}} 看似简单,上线后改个权限就得发版重启,集群多实例还会出现缓存不一致。线上系统必须支持热更新、可审计、可关联日志。
- 建三张表:
roles(含id,name)、permissions(含code,description)、role_permissions(字段为role_id和permission_code,不用permission_id,方便后期重构 code) - 缓存 key 建议用
role:<role_name>:permissions</role_name>或user:<id>:permissions</id>,过期时间设 10–30 分钟,DB 回源时加读锁防击穿 - 禁止在代码里用中文或空格作
code,比如"用户管理-查看"—— 这会让 JSON 解析、Redis 查询、日志 grep 全部变麻烦
JWT 不能只校验签名,必须检查 exp 和 iat
很多项目用 golang-jwt/jwt/v5 解析 token,但只调了 token.Valid,漏掉时间校验,导致过期 token 仍能访问敏感接口。这不是小问题,是安全红线。
初始化并管理阿里云SDK Go 客户端,涵盖 sync.Once 单例、goroutine 安全、endpoint 与 region 配置、VPC 端点及调试。
- 解析时务必显式验证时间字段:
claims.VerifyExpiresAt(time.Now(), true)和claims.VerifyIssuedAt(time.Now(), true) - 别把
role直接当权限用——JWT payload 里放"role": "editor"没问题,但权限判断仍要查该角色绑定了哪些permission_code,否则换角色就得重发 token - 生产环境禁用
"your-secret-key"这类硬编码密钥,用环境变量加载,并确保长度 ≥32 字节
前端菜单和按钮权限不是后端甩个数组就完事
后端返回 ["user:read", "order:write"],前端按这个数组控制按钮显隐?远远不够。真实场景里,用户可能有 user:read 权限,但只能看自己创建的用户(数据级权限),或者能看到菜单但点进去报 403(后端没做行级过滤)。
立即学习“go语言免费学习笔记(深入)”;
- 菜单是否显示,由前端根据权限数组过滤;但「点开后能不能查到数据」「删按钮点了会不会真删掉」,这两件事必须由后端兜底
- 不要在中间件里做
WHERE user_id = ?这种过滤——它不知道当前 handler 要查哪个 ID,得在 service 层结合c.MustGet("user").(*User).ID动态拼条件 - 最易忽略的一点:API 文档和 Swagger 必须标注每个接口所需的
permission_code,否则前后端对不齐,测试也覆盖不到边界 case
权限系统最难的不是写中间件,而是让「角色定义」「权限分配」「缓存刷新」「数据过滤」四件事在不同服务、不同实例间保持一致。一旦某台机器缓存没清,或者某个 handler 忘了调 RequirePermission("xxx"),漏洞就藏进去了。

















