在JWT令牌中存储用户权限的最佳实践是什么?
JWT结合细粒度用户权限体系的最优实践
针对你遇到的「用户细粒度权限写入JWT导致payload体积过大影响传输」的问题,核心是平衡「无状态校验效率」和「令牌体积控制」,行业内的成熟实践如下:
方案1:权限分层存储(最优通用方案)
这是绝大多数业务场景下的首选方案,兼顾性能、体积和灵活性:
- JWT payload中仅保留用户ID、过期时间、角色这类体积极小的粗粒度核心标识,完全不存放具体权限点
- 服务端引入Redis分布式缓存,以
user:perm:{userId}为key存储对应用户的全量权限集合,缓存过期时间和JWT的有效期保持一致 - 首次请求时仅查1次数据库加载权限写入缓存,后续所有请求直接查缓存完成权限校验,平均延迟和本地JWT校验基本持平
- 权限更新时直接删除对应用户的缓存key,下次请求自动加载最新权限,还能解决JWT存权限无法即时生效的遗留问题
方案2:权限压缩编码(适用于必须完全无状态的场景)
如果你的架构要求服务端完全无状态、不允许引入缓存,可以通过编码压缩控制JWT体积:
- 提前枚举系统全量权限点,每个权限对应一个唯一短编码(比如1-2位的数字/字符),替代完整权限名称字符串(比如用
03代替user:delete) - 权限总数≤64时,直接用位掩码存储权限集合:用一个Long类型数字的每一位代表一个权限是否开启,整个权限集合仅占8字节,校验时直接通过位运算
(permMask & targetPermBit) != 0完成,性能远高于字符串匹配 - 对JWT payload做gzip压缩后再进行Base64编码,可额外降低30%左右的体积
方案3:双令牌体系(适用于前后端分离、前端有页面权限控制需求的场景)
- 拆分出两类JWT:
- 体积极小的
access_token,仅存用户ID、过期时间等核心字段,接口请求时携带,完全不影响传输效率 - 存储全量角色、权限信息的
perm_token,仅在用户登录时返回给前端本地存储,用于前端页面权限判断,无需随接口请求携带
- 体积极小的
- 服务端接口权限校验仍走缓存查询逻辑,不依赖令牌中存储的权限字段,同时满足前后端的权限控制需求
注意:不要为了追求完全无状态强行把所有业务信息塞入JWT,JWT的核心价值是防篡改的身份凭证,合理结合服务端缓存才是性价比最高的实践方式。
内容的提问来源于stack exchange,提问作者waqar
相关产品推荐
相关产品推荐

