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

  1. Have the user log in again to obtain a fresh token — this is expected behavior for session expiry.
  2. If sessions expire too quickly, increase the JWT TTL in configuration (jeecg.jwt.expireTime) and the Redis cache TTL accordingly.
  3. Ensure Redis persistence is configured (AOF/RDB) so token caches survive Redis restarts.
  4. 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

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.