|
@@ -5,8 +5,9 @@ import axios from 'axios';
|
|
|
import router from '@/router';
|
|
import router from '@/router';
|
|
|
|
|
|
|
|
import { MessageBox, Message } from 'element-ui';
|
|
import { MessageBox, Message } from 'element-ui';
|
|
|
-import { API_BASE_URL, TOKEN_HEADER_NAME, LAYOUT_PATH } from '@/config/setting';
|
|
|
|
|
|
|
+import { API_BASE_URL, TOKEN_HEADER_NAME, LAYOUT_PATH, TENANT_HEADER_NAME } from '@/config/setting';
|
|
|
import { getToken, setToken } from './token-util';
|
|
import { getToken, setToken } from './token-util';
|
|
|
|
|
+import { getTenantId } from './tenant-util';
|
|
|
import { logout } from './page-tab-util';
|
|
import { logout } from './page-tab-util';
|
|
|
import JSONBIG from 'json-bigint';
|
|
import JSONBIG from 'json-bigint';
|
|
|
|
|
|
|
@@ -25,16 +26,39 @@ const service = axios.create({
|
|
|
}
|
|
}
|
|
|
]
|
|
]
|
|
|
});
|
|
});
|
|
|
|
|
+/**
|
|
|
|
|
+ * 是否为签发登录凭证的入口(对应后端 TenantIsolationAspect 的 LOGIN_URIS)。
|
|
|
|
|
+ * @param {string} url 请求地址
|
|
|
|
|
+ * @returns {boolean} 是登录入口返回 true
|
|
|
|
|
+ */
|
|
|
|
|
+function isLoginEntry(url) {
|
|
|
|
|
+ return typeof url === 'string' && /(^|\/)user\/login(\?|$)/.test(url);
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
/**
|
|
/**
|
|
|
* 添加请求拦截器
|
|
* 添加请求拦截器
|
|
|
*/
|
|
*/
|
|
|
|
|
+
|
|
|
service.interceptors.request.use(
|
|
service.interceptors.request.use(
|
|
|
(config) => {
|
|
(config) => {
|
|
|
// 添加 token 到 header
|
|
// 添加 token 到 header
|
|
|
- const token = getToken();
|
|
|
|
|
|
|
+ // 登录入口必须以匿名身份发出:残留的旧凭证在服务端优先级高于请求头
|
|
|
|
|
+ // (token 的租户声明才是权威),它既会顶掉本次选择的租户,又会让 X-Tenant-ID
|
|
|
|
|
+ // 被当成外部伪造而忽略 —— 表现为"选了租户却登进平台库"。
|
|
|
|
|
+ const token = isLoginEntry(config.url) ? '' : getToken();
|
|
|
if (token && config.headers) {
|
|
if (token && config.headers) {
|
|
|
config.headers.common[TOKEN_HEADER_NAME] = token;
|
|
config.headers.common[TOKEN_HEADER_NAME] = token;
|
|
|
}
|
|
}
|
|
|
|
|
+ // 多租户:未登录的请求(登录接口、登录页品牌标识、扫码入职等匿名入口)租户只能靠
|
|
|
|
|
+ // 请求头传递 —— 服务端必须在认证之前就知道连哪个租户库。
|
|
|
|
|
+ // 已登录时租户已写入 token 声明、服务端以声明为准,这里不重复携带,
|
|
|
|
|
+ // 避免为"多余且会被忽略"的头部逐个打告警日志。
|
|
|
|
|
+ if (!token && config.headers) {
|
|
|
|
|
+ const tenantId = getTenantId();
|
|
|
|
|
+ if (tenantId) {
|
|
|
|
|
+ config.headers.common[TENANT_HEADER_NAME] = tenantId;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
return config;
|
|
return config;
|
|
|
},
|
|
},
|
|
|
(error) => {
|
|
(error) => {
|