{"record":{"id":"d9657d0843278a58","repo":"jeecgboot/JeecgBoot","slug":"error-d9657d","errorCode":null,"errorMessage":"登录租户授权变更，请重新登陆!","messagePattern":"登录租户授权变更，请重新登陆!","errorType":"exception","errorClass":"AuthenticationException","httpStatus":401,"severity":"warning","filePath":"jeecg-boot/jeecg-boot-base-core/src/main/java/org/jeecg/config/shiro/ShiroRealm.java","lineNumber":178,"sourceCode":"                    boolean isAuthorization = false;\n                    //========================================================================\n                    // 查询用户信息（如果租户不匹配从数据库中重新查询一次用户信息）\n                    String loginUserKey = CacheConstant.SYS_USERS_CACHE + \"::\" + username;\n                    redisUtil.del(loginUserKey);\n                    LoginUser loginUserFromDb = commonApi.getUserByName(username);\n                    if (oConvertUtils.isNotEmpty(loginUserFromDb.getRelTenantIds())) {\n                        String[] newArray = loginUserFromDb.getRelTenantIds().split(\",\");\n                        if (oConvertUtils.isIn(contextTenantId, newArray)) { \n                            isAuthorization = true;\n                        }\n                    }\n                    //========================================================================\n\n                    //*********************************************\n                    if(!isAuthorization){\n                        log.info(\"租户异常——登录租户：\" + contextTenantId);\n                        log.info(\"租户异常——用户拥有租户组：\" + userTenantIds);\n                        throw new AuthenticationException(\"登录租户授权变更，请重新登陆!\");\n                    }\n                    //*********************************************\n                }\n            }\n        }\n        return loginUser;\n    }\n\n    /**\n     * JWTToken刷新生命周期 （实现： 用户在线操作不掉线功能）\n     * 1、登录成功后将用户的JWT生成的Token作为k、v存储到cache缓存里面(这时候k、v值一样)，缓存有效期设置为Jwt有效时间的2倍\n     * 2、当该用户再次请求时，通过JWTFilter层层校验之后会进入到doGetAuthenticationInfo进行身份验证\n     * 3、当该用户这次请求jwt生成的token值已经超时，但该token对应cache中的k还是存在，则表示该用户一直在操作只是JWT的token失效了，程序会给token对应的k映射的v值重新生成JWTToken并覆盖v值，该缓存生命周期重新计算\n     * 4、当该用户这次请求jwt在生成的token值已经超时，并在cache中不存在对应的k，则表示该用户账户空闲超时，返回用户信息已失效，请重新登录。\n     * 注意： 前端请求Header中设置Authorization保持不变，校验有效性以缓存中的token为准。\n     *       用户过期时间 = Jwt有效时间 * 2。\n     *\n     * @param userName","sourceCodeStart":160,"sourceCodeEnd":196,"githubUrl":"https://github.com/jeecgboot/JeecgBoot/blob/96fb33f5ec68516da0b0147da06b2eb0419e063a/jeecg-boot/jeecg-boot-base-core/src/main/java/org/jeecg/config/shiro/ShiroRealm.java#L160-L196","documentation":"Thrown by ShiroRealm.checkUserTokenIsEffect() during multi-tenant validation when the tenant ID in the request context (TenantContext) does not match any tenant ID in the user's relTenantIds, even after re-querying the database for fresh data. This detects when a user's tenant authorization was revoked or changed after login — the token is still valid but the tenant access is no longer authorized.","triggerScenarios":"Admin removes a tenant from a user's relTenantIds while the user is logged in with that tenant selected; user switches tenant in the front-end but their authorization was revoked; the X-TENANT-ID header in the request does not match any tenant the user currently has access to.","commonSituations":"Admin reassigns tenant permissions after an organizational change; user's tenant contract expired; tenant ID was manually set in the request header to a value the user lost access to; multi-tenant data was migrated and tenant assignments changed.","solutions":["Have the user log out and log in again to get a fresh token with updated tenant assignments.","Administrator verifies the user's current tenant assignments in sys_user.rel_tenant_ids.","If the tenant assignment is correct but the token is stale, clear the user's Redis cache (SYS_USERS_CACHE key) and have them re-login.","Check that the front-end sends the correct X-TENANT-ID header matching the user's assigned tenant."],"exampleFix":"-- Verify user's tenant assignments\nSELECT username, rel_tenant_ids FROM sys_user WHERE username = '<username>';\n-- If tenant was removed, re-add it:\nUPDATE sys_user SET rel_tenant_ids = '0,1,2' WHERE username = '<username>';\n-- Clear user cache, then user logs out and logs in again.","handlingStrategy":"try-catch","validationCode":"// Verify tenant assignment before relying on a cached token\n// Admin: SELECT username, rel_tenant_ids FROM sys_user WHERE username = '<username>'\n// If tenant was removed, re-add it before the user tries to access","typeGuard":null,"tryCatchPattern":"// Handled by JwtFilter — returns 401 '登录租户授权变更'\n// Front-end: on this message, force logout and re-login\naxios.interceptors.response.use(null, error => {\n    if (error.response?.data?.message?.includes('租户授权变更')) {\n        store.dispatch('Logout');\n        router.push('/user/login');\n    }\n});","preventionTips":["When modifying tenant assignments, clear the affected user's Redis cache (SYS_USERS_CACHE key).","Have users re-authenticate after tenant authorization changes.","Ensure the front-end sends the correct X-TENANT-ID header matching the user's assigned tenant."],"tags":["shiro","jwt","authentication","multi-tenant","tenant-authorization"],"backgroundTag":null,"analyzedSha":"96fb33f5ec68516da0b0147da06b2eb0419e063a","analyzedAt":"2026-08-14T00:04:16.786Z","schemaVersion":2},"datasetVersion":"2026-08-14T00:17:13.853Z"}