jeecgboot/JeecgBoot · warning · AuthenticationException
Token失效,请重新登录!
Error message
Token失效,请重新登录!
What it means
Thrown by ShiroRealm.checkUserTokenIsEffect() when jwtTokenRefresh() returns false — the token has expired and is no longer refreshable. The method checks the Redis cache (PREFIX_USER_TOKEN + token) for a stored copy; if the cache entry is gone (TTL expired) or the stored token no longer verifies, refresh fails. The actual error message may be overridden by a per-token error message stored in Redis (PREFIX_USER_TOKEN_ERROR_MSG). CommonConstant.TOKEN_IS_INVALID_MSG is the default 'Token失效,请重新登录!' message.
Source
Thrown at jeecg-boot/jeecg-boot-base-core/src/main/java/org/jeecg/config/shiro/ShiroRealm.java:146
throw new AuthenticationException("Token非法无效!");
}
// 查询用户信息
log.debug("———校验token是否有效————checkUserTokenIsEffect——————— "+ token);
LoginUser loginUser = TokenUtils.getLoginUser(username, commonApi, redisUtil);
//LoginUser loginUser = commonApi.getUserByName(username);
if (loginUser == null) {
throw new AuthenticationException("用户不存在!");
}
// 判断用户状态
if (loginUser.getStatus() != 1) {
throw new AuthenticationException("账号已被锁定,请联系管理员!");
}
// 校验token是否超时失效 & 或者账号密码是否错误
if (!jwtTokenRefresh(token, username, loginUser.getPassword())) {
// 用户登录Token过期提示信息
String userLoginTokenErrorMsg = oConvertUtils.getString(redisUtil.get(CommonConstant.PREFIX_USER_TOKEN_ERROR_MSG + token));
throw new AuthenticationException(oConvertUtils.isEmpty(userLoginTokenErrorMsg)? CommonConstant.TOKEN_IS_INVALID_MSG: userLoginTokenErrorMsg);
}
// 代码逻辑说明: 校验用户的tenant_id和前端传过来的是否一致
String userTenantIds = loginUser.getRelTenantIds();
if(MybatisPlusSaasConfig.OPEN_SYSTEM_TENANT_CONTROL && oConvertUtils.isNotEmpty(userTenantIds)){
String contextTenantId = TenantContext.getTenant();
log.debug("登录租户:" + contextTenantId);
log.debug("用户拥有那些租户:" + userTenantIds);
//登录用户无租户,前端header中租户ID值为 0
String str ="0";
if(oConvertUtils.isNotEmpty(contextTenantId) && !str.equals(contextTenantId)){
// 代码逻辑说明: /issues/I4O14W 用户租户信息变更判断漏洞
String[] arr = userTenantIds.split(",");
if(!oConvertUtils.isIn(contextTenantId, arr)){
boolean isAuthorization = false;
//========================================================================
// 查询用户信息(如果租户不匹配从数据库中重新查询一次用户信息)
String loginUserKey = CacheConstant.SYS_USERS_CACHE + "::" + username;
redisUtil.del(loginUserKey);View on GitHub (pinned to 96fb33f5ec)
Solutions
- Have the user log in again to obtain a fresh token — this is expected behavior for session expiry.
- If sessions expire too quickly, increase the JWT TTL in configuration (jeecg.jwt.expireTime) and the Redis cache TTL accordingly.
- Ensure Redis persistence is configured (AOF/RDB) so token caches survive Redis restarts.
- Check if a password change or admin action intentionally invalidated the token.
Example fix
// No code fix — expected session expiry. // To extend session lifetime, adjust application.yml: // jeecg: // jwt: // expireTime: 3600000 # 1 hour JWT TTL (ms) // # Redis cache TTL is automatically set to 2x this value // Front-end: on 401 'Token失效', redirect to login page automatically.
Defensive patterns
Strategy: try-catch
Validate before calling
// Front-end: track token age and proactively refresh before expiry
const tokenAge = Date.now() - parseInt(localStorage.getItem('token-issued-at'));
if (tokenAge > TOKEN_TTL * 0.8) {
await refreshToken(); // or redirect to login
} Try / catch
// Handled by JwtFilter — returns 401 'Token失效'
// Front-end interceptor:
axios.interceptors.response.use(null, error => {
if (error.response?.status === 401) {
store.dispatch('Logout');
router.push('/user/login');
}
}); Prevention
- Configure JWT TTL to match expected session duration (jeecg.jwt.expireTime).
- Ensure Redis persistence (AOF/RDB) so token caches survive restarts.
- Use front-end token refresh/silent-renew before expiry.
- After password changes, clear old tokens from Redis.
When it happens
Trigger: User's session has been idle longer than the JWT max lifetime (JWT TTL * 2); Redis was flushed or restarted losing the token cache; password was changed invalidating the old token signature; the token cache entry was explicitly deleted (e.g., by admin force-logout).
Common situations: User leaves the application idle overnight and returns to find their session expired; Redis restart/flush; password change on another device; admin forces all users to re-authenticate by clearing Redis token caches; token TTL configuration is too short.
Related errors
AI-assisted analysis of jeecgboot/JeecgBoot@96fb33f5ec (2026-08-14).
Data as JSON: /api/errors/d716b5799acd3cf8.
Report an issue: GitHub.