工程实践
SpringBoot 前后端分离 JWT 认证完整落地与坑点
JWT 无状态鉴权落地不难,难的是把密钥、过期时间、敏感数据和全局拦截这些坑都填平。
前后端分离的项目做认证,第一个想到的往往是 JWT。我用它做了几个项目,今天把落地过程和一些踩过的坑一起写下来。
先说说为什么不用传统的 Session。Session 会话数据存在服务端内存里,一旦上分布式集群,就得靠 Redis 做会话同步,架构一下就复杂了;跨域请求又不会自动带 SessionId,前后端分离下适配很麻烦;多端登录(网页、小程序、App)更是撑不住。这些都是 Session 的天然短板。
JWT 到底是怎么工作的
JWT 的卖点是"无状态":用户身份、权限、过期时间这些信息加密打包在令牌里,服务端不用存会话,只用密钥校验签名。校验通过就放行,不通过就拒绝,多端、分布式都好使。
它的结构是三段式:Header(声明算法)、Payload(存放用户信息)、Signature(签名)。Header 和 Payload 只是 Base64 编码,签名才是关键——它是用密钥对前两段做 HMAC(HS256)或 RSA(RS256)签出来的。服务端拿到令牌,重新算一遍签名,对得上就说明令牌没被篡改过。需要说清楚的是,Payload 是明文,不是加密,任何人都能解出来看。
这里顺带说下 HS256 和 RS256 的区别:HS256 是对称加密,签发和校验用同一个密钥,简单但密钥要保密,适合内部系统;RS256 是非对称,私钥签发、公钥校验,适合多服务或第三方要验签的场景。个人站用 HS256 就够,但别把密钥写进代码。
落地流程其实不复杂:登录验证账号密码 → 生成令牌 → 前端每次请求放 Authorization 头里 → 后端过滤器校验签名 → 通过后放行。闭环就这五步。
四个必须避开的坑
但坑也基本都集中在"不规范"三个字上,我一个个说。
第一,密钥千万别硬编码在代码里。密钥一泄露,谁都能伪造令牌,等于整个认证体系裸奔。必须配置化、托管在环境变量里,最好用环境管理工具统一管理。
第二,Token 过期时间别贪长。JWT 有个硬伤——签发之后没法主动作废。过期时间设太长,账号被盗了你也吊销不了,只能干瞪眼。所以业界通用做法是双令牌:短时效的 AccessToken(比如 15 分钟)负责日常请求,长时效的 RefreshToken(比如 7 天)负责续期,RefreshToken 走服务端保存,这样至少能吊销。这套"双令牌 + 刷新"机制,是生产环境的基本功。还有个细节:AccessToken 过期后,前端要能自动用 RefreshToken 换新的,不能一过期就让用户重新登录。
第三,Payload 里别塞敏感数据。JWT 的 Payload 只是 Base64 编码,不是加密,任何人拿到都能解出来。身份证号、手机号这些千万别往里面放,只放用户 ID 这种非敏感标识。
第四,接口一定要全局拦截。我见过有项目只拦了一部分接口,管理后台的接口裸奔在公网上,随便调。所有需要鉴权的接口必须统一走过滤器,一个都不能漏。可以做个注解 + AOP 的方式,给需要鉴权的接口打标记,统一进拦截逻辑。还要注意"放行名单"要小——只有登录、注册、验证码这类接口能放行,其他全部进拦截。
别忘了配合的安全措施
除了上面四条,还有几个配合措施值得做:一是 CSRF 防护,如果前端用 Cookie 存令牌,要防跨站请求伪造,用 SameSite 属性 + CSRF Token;二是加登录失败限流,防止暴力破解,比如同 IP 一分钟内失败超过 5 次就锁一会;三是给接口配 HTTPS,别让令牌在网络上裸奔;四是记录登录审计日志,出问题能溯源。
最后补一句:JWT 的"无状态"也别过度美化。真正无状态带来的就是吊销困难,所以生产项目往往还是要服务端存一份 RefreshToken 或会话状态。选 Session 还是 JWT,取决于你有多端需求、是否分布式部署、是否必须主动吊销——没有绝对谁更好,只有适不适合你的场景。对个人站这种单服务、少并发的场景,用 JWT + 双令牌已经是很稳的组合了。
如果你在这里有了 10 分钟的顿悟,那它折叠得刚刚好。
