
简介这是一份关于若依框架设置Token过期时间的源码配置包面向使用若依开发前后端分离项目的开发者解决会话时长调整与前后端同步问题。资源共6个文件压缩包约7KB主要包含application.yml、request.js两个核心配置以及html、markdown说明、gitignore等辅助文件便于对照修改和理解整体结构。针对默认30分钟有效期偏短、用户频繁重新登录的场景资料提供了将后端expireTime与前端axios的timeout统一调整为2小时的具体方案同时介绍了refresh token刷新机制及其安全注意事项能帮助开发者避免因前后端过期时间不一致导致的访问中断。已有191人学习使用适合刚接触若依框架、希望快速掌握Token生命周期管理并保障系统安全性的初中级开发人员。1. 项目核心拆解若依的token机制到底怎么运转的1.1 先搞清楚若依做了什么若依RuoYi是目前国内中小团队用得非常多的一套后台管理系统前后端分离版本用的是Spring Boot Vue这套组合。你搜索“若依框架token过期设置”大概率是碰到两种情况要么是token到期后用户被强制下线体验太差要么是改了配置文件里登录失效相关参数结果发现根本不生效甚至直接登录报错。先说结论若依本身的token设计是一个JWT Redis双重校验的结构。JWT负责“证明你是谁”Redis负责“记录你登录后有哪些权限、能访问哪些菜单”两者结合后才能完成一次完整的身份认证。所以当你单独去调JWT的过期时间或者只改Redis的失效策略都会发现行为不符合预期。我在项目里初期也踩过这个坑以为只要把前端request.js里的超时时间改大就行结果token还是半小时就失效。后来看了源码才发现若依的token有效期完全由后端控制前端那层超时只是网络请求层面的限制跟业务层的token过期是两码事。1.2 JWT到底是什么为什么要用JWTJWTJSON Web Token本质上是一个经过签名处理的JSON字符串由三部分组成Header头部、Payload负载、Signature签名。三部分用点号拼接形如xxxxx.yyyyy.zzzzz。若依生成的token里Payload部分主要放了两个东西login_user_key一个UUID字符串用来关联Redis中存储的用户登录信息签发时间、过期时间等元数据这里要理解一个关键设计若依并没有把用户信息塞进JWT本身虽然JWT支持这么干而是只在JWT里放了一个“钥匙”真正的用户信息、权限列表、角色信息都存在Redis里key的命名规则是login_tokens:uuid。这样做的好处是当管理员在后台修改了用户权限不需要等JWT过期就能立即生效因为权限实时从Redis读取。缺点是一旦Redis里那条数据被清了不管你JWT还有多久过期请求都会被判定为未登录。这就是为什么有时候明明“token没过期”却突然被踢下线的原因。2. 源码逐行读TokenService才是真正的命门2.1 创建token时发生了什么找到ruoyi-framework模块下的com.ruoyi.framework.web.service.TokenService这是整个token逻辑的核心类。创建token的核心方法叫createToken流程是这样的public MapString, Object createToken(LoginUser loginUser) { // 生成唯一标识 String tokenId UUID.fastUUID().toString(); loginUser.setTokenId(tokenId); // 刷新过期时间 refreshToken(loginUser); // JWT中只放uuid作为key MapString, Object claims new HashMap(); claims.put(LOGIN_USER_KEY, tokenId); String token Jwts.builder() .setClaims(claims) .signWith(SignatureAlgorithm.HS512, secret) .compact(); return token; }refreshToken里做了一件事把LoginUser对象序列化后塞进Redis同时设置了过期时间。过期时间的值不是写死的而是从配置类TokenConfig以及application.yml中读取的。2.2 过期时间到底在哪里配置这是很多新手最容易迷路的地方。看若依前端的login.js登录成功后前端会拿到一个token字符串保存在cookie里但前端代码里根本找不到过期时间的设置。真正的控制点在后端的application.ymltoken: # 令牌自定义标识 header: Authorization # 令牌密钥 secret: abcdefghijklmnopqrstuvwxyz # 令牌有效期默认30分钟 expireTime: 30这里的expireTime单位是分钟默认30。它会被注入到TokenService里在每次登录成功创建token时通过TimeUnit.MINUTES.toMillis(expireTime)换算成毫秒再写入Redis。细心的读者会发现这个配置同时影响了两个层面Redis里login_tokens:uuid这个key的过期时间JWT本身的过期时间那么校验的时候是两层都校验吗实际逻辑是若依的拦截器先从header里取出JWT用密钥解密拿到login_user_key然后拿着这个key去Redis查LoginUser。如果查不到直接抛出“认证失败无法访问系统资源”如果查到了说明token有效继续后续的权限校验。也就是说Redis的存在是最高优先级Redis里没了JWT再有效也没用。2.3 为什么项目里改配置没生效的排查思路我在自己项目里遇到过这种情况把expireTime改成了120分钟重启后端后登录发现还是会过期。排查了大半天最后发现是改了后端的配置但没看代码里是否存在多数据源配置覆盖若依在读取这个值时有一段逻辑如果配置中心或环境变量里存在同名配置会优先用环境变量的值。还有一种非常常见的情况你改的是application-druid.yml或者application-prod.yml但启动时激活的是dev环境配置文件没生效。排查方法很简单启动后看控制台或日志里有没有类似Token expire time: 30 minutes的打印具体打印取决于日志级别。若依在TokenService的构造阶段会读取配置值如果你能在日志里看到实际加载的值就说明配置生效了。3. 让token“动起来”四种常用续期方案实战对比3.1 方案一Redis自动续期门槛最低若依默认行为是固定过期也就是从登录那一刻起倒计时30分钟不管你有没有操作。这个方案的问题很明显用户用着用着突然被踢下线体验很差。最简单粗暴的改进方式利用Redis的expire命令在每次有请求过来时如果发现这个token对应的Redis key即将过期就重新设置过期时间。这种方案我称之为“滑动过期”。实现思路并不复杂在TokenService的getLoginUser方法里加一段续期逻辑public LoginUser getLoginUser(HttpServletRequest request) { // 原有解析token逻辑... String tokenId parseToken(request); if (StringUtils.isNotEmpty(tokenId)) { String key getTokenKey(tokenId); LoginUser user redisCache.getCacheObject(key); if (user ! null) { // 每次访问都重新刷新过期时间实现滑动续期 refreshToken(user); // 复用原有刷新方法 } return user; } return null; }这里refreshToken就是源码里给Redis重新设值的那个方法复用即可。每次请求都会把过期时间重置为30分钟用户只要在30分钟内有过任何操作就永远不会掉线。产品方如果要求“半小时无操作才登出”这就是最贴合需求的方案。踩坑提示这个方法会频繁写Redis。虽然性能影响不大但如果并发很高建议在续期前判断一下剩余时间比如剩余低于10分钟才去续期减少无意义的写操作。3.2 方案二利用Redis lazy过期机制如果说方案一是“主动续期”那方案二就是“延迟判断”。Redis本身对带过期时间的key有一种惰性删除机制只有当key被访问时才会去检查是否过期过期就删除。基于这个特性你可以在Redis的value里额外存一个“最后活跃时间”字段。每次请求进来只更新时间戳不重置Redis的过期时间Redis的过期时间设成一个较大的值比如7天交给业务层判断“最后活跃时间”距今有没有超过30分钟。这个方案的优点在于大量请求只写一个字段不会频繁刷新Redis过期时间性能上更优缺点是Redis里会堆积大量已失效但未删除的key如果登录用户量大内存占用会明显上升。实际项目中我用过一次这个方案后来觉得内存开销不划算又改回了方案一。如果用户基数小比如几千人其实方案二也完全可行。3.3 方案三自定义注解加AOP灵活度高如果你不想动若依的核心代码又希望某些接口或某些角色采用不同的过期策略那就用自定义注解配合AOP切片来实现。定义注解TokenRefresh(interval 30)然后写一个切面在带有该注解的方法执行前手动调用TokenService的刷新方法Aspect Component public class TokenRefreshAspect { Autowired private TokenService tokenService; Before(annotation(tokenRefresh)) public void before(JoinPoint joinPoint, TokenRefresh tokenRefresh) { HttpServletRequest request ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest(); tokenService.refreshTokenByRequest(request); } }这个方法的好处是可以只对核心业务接口续期比如文件上传、长报表导出而对查询类接口不做续期在资源和体验之间取平衡。坏处是自己要多维护一套切面代码而且如果拦截器里已经做了续期两者会冲突需要设计好优先级。3.4 方案四双token机制项目选型参考双token是移动端常见的做法一个access token短时效比如2小时用于正常请求一个refresh token长时效比如7天专门用于换取新的access token。用户拿着refresh token去调用刷新接口后端校验refresh token有效性后签发新的access token。若依的架构本身没有这种设计要改造需要动的地方比较多前端需要存两个token后端要新增刷新接口还要处理refresh token被重放的风险。我通常在以下几种场景才会推荐双token移动端App用户希望“登录一次七天有效”安全要求高access token要尽量短后台管理端则完全没必要滑动续期就足够好所以如果只是在做后台管理系统我建议优先考虑方案一如果是做面向C端的App再认真考虑方案四。4. 常见问题与排查技巧实录4.1 高频问题速查表现象根因解决方案token设置30分钟后依然很快失效Redis里有别的定时任务清了key排查是否有脚本执行flushdb或按前缀批量删除修改配置后重启不生效启动环境加载了其他配置文件检查spring.profiles.active激活的是哪个环境登录报“令牌不能为空”前端没有正确携带header确认请求头名称为Authorization且带Bearer前缀跨域条件下token丢失前端axios没有配置withCredentials或CORS头不完整检查CORS配置允许携带认证信息明明是同一账号两个浏览器互相顶下线若依默认是多端互踢多个登录态并存需自行改造不能用默认逻辑系统闲置一段时间后首次请求特别慢token已过期前端重新走登录路由且重新拉取资源改成滑动续期方案让活跃用户一直保持有效这里面最容易被忽略的是第一条。若依的Redis key有统一前缀login_tokens:如果项目里加了定时任务定期清理以某些前缀开头的key很有可能会把登录态一起清了。用redis-cli --scan --pattern login_tokens:*看一眼实际剩余的key数量就能快速确认。4.2 前端配合改动别只改后端后端改造只做了一半前端也得同步配合。若依前端在request.js里有一段响应拦截当后端返回状态码401时会跳转到登录页面。如果你只是把后端续期延长但前端把token保存在cookie里的expires设得很短用户在token有效期内刷新页面cookie反而先没了一样会被踢出。所以建议在调整后端方案的同时把前端保存token的cookie有效期改成比较长比如7天同时清理一下长期记住我勾选逻辑。具体修改位置在utils/auth.js里export function setToken(token) { return Cookies.set(TokenKey, token, { expires: 7 }) }这里有个细节如果你的后端做了滑动续期那么前端每次请求成功后其实可以把新的token如果有的话重新写入cookie。但若依默认不会在每次请求时签发新token所以这个改动属于锦上添花不做也不影响主流程。4.3 Nginx下刷新404与token的关系热搜词里有一条“若依框架的前端部署到nginx里面f5刷新会404”这个问题虽然不是token直接引起的但和token机制叠加在一起会让排查变得复杂。刷新404的本质是前端路由用了history模式nginx没有做try_files回退。但登录成功后刷新页面前端会重新加载并校验token如果此时404了会让人误以为token丢了。排查时先确认nginx配置location / { try_files $uri $uri/ /index.html; }加上这行后刷新回到首页的问题就解决了。然后再看token是否因为页面跳转丢失——很多时候是因为前端代码在接口401时强制清了cookie而刷新时页面还没加载完请求就被拦截了最终看起来像“刷新一次就退出登录”。我建议排查顺序是先看nginx回退配置再看前端request.js的响应拦截最后看后端日志里是否有token解析失败的记录。4.4 关于“token用量”和“credits换算token”这类搜索词的提醒热词里还出现了“token用量”、“2500credits相当于多少token”这类词这些其实是ChatGPT等大模型场景下的token概念和若依框架的认证token完全是两码事。建议搜索时加上“若依”或“JWT”等限定词避免浪费时间看一堆无关内容。大模型的token是指文本切分的最小单位跟本篇讨论的身份认证令牌不是同一个东西不要混为一谈。5. 写在最后的经验总结做了这么多年后台系统我最大的体会是token过期设置没有银弹完全取决于业务形态。如果你给甲方做后台管理系统用户大概率不是天天盯着页面看而是时不时地看一眼这时候最怕的就是用户回来发现被下线了。滑动续期方案方案一基本能覆盖绝大多数管理端场景实现成本低、逻辑直观、排查也容易。如果你做的是对外开放的API服务安全团队会要求token短时效那就别嫌麻烦把双token方案做了至少能应对审计的追问。另外有一点要特别提醒无论你选哪种方案改动后一定要做token过期边界测试。也就是把过期时间临时改成1分钟然后分别测“1分钟内持续操作”“1分钟后操作”“改Redis里的key后操作”这三种情况确保行为符合预期再上线。我见过太多人改完代码只测了正常登录登出没测边界情况上线后被用户骂成筛子。最后再分享一个小技巧如果实在不想改源码但又觉得默认30分钟太短直接把application.yml里token.expireTime调大比如120分钟或480分钟是最快的办法。记得同时确认Redis的maxmemory策略不是allkeys-lru否则内存紧张时Redis会优先淘汰掉一部分登录key造成偶发掉线。真遇到这种情况设置maxmemory-policy volatile-lru让Redis只淘汰带过期时间的key能减少误伤。本文还有配套的精品资源点击获取