|
|
@@ -110,4 +110,101 @@ public class TenantChannelContext {
|
|
|
DynamicDataSourceContextHolder.clearDataSourceType();
|
|
|
SecurityContextHolder.clearContext();
|
|
|
}
|
|
|
+
|
|
|
+ /**
|
|
|
+ * javax.websocket 握手阶段专用:根据 tenantCode 查库,将 tenantId/dsKey 存入 userProperties。
|
|
|
+ * 在 WebSocketConfigurator.modifyHandshake() 中调用一次,后续 onOpen/onMessage/onClose 无需再查库。
|
|
|
+ */
|
|
|
+ public void resolveAndStore(String tenantCode, java.util.Map<String, Object> userProperties) {
|
|
|
+ if (!saasEnabled || StringUtils.isBlank(tenantCode)) return;
|
|
|
+ try {
|
|
|
+ DynamicDataSourceContextHolder.setDataSourceType(DataSourceType.MASTER.name());
|
|
|
+ TenantInfo query = new TenantInfo();
|
|
|
+ query.setTenantCode(tenantCode);
|
|
|
+ List<TenantInfo> list = tenantInfoService.selectTenantInfoList(query);
|
|
|
+ if (list == null || list.isEmpty()) {
|
|
|
+ log.warn("[SaaS WS] resolveAndStore: tenantCode={} 未找到租户", tenantCode);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ TenantInfo tenant = list.get(0);
|
|
|
+ if (!Integer.valueOf(1).equals(tenant.getStatus())) return;
|
|
|
+ if (tenant.getExpireTime() != null && tenant.getExpireTime().before(new Date())) return;
|
|
|
+ // 确保数据源已注册
|
|
|
+ tenantDataSourceManager.switchTenant(tenant);
|
|
|
+ userProperties.put("_tenantId", tenant.getId());
|
|
|
+ userProperties.put("_dsKey", "tenant:" + tenant.getId());
|
|
|
+ log.info("[SaaS WS] 握手阶段绑定租户 tenantId={}, tenantCode={}", tenant.getId(), tenantCode);
|
|
|
+ } finally {
|
|
|
+ DynamicDataSourceContextHolder.clearDataSourceType();
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * javax.websocket 业务处理前专用:从 userProperties 取 tenantId/dsKey 直接激活,无需查库。
|
|
|
+ * 在 onOpen/onMessage/onClose 开头调用。
|
|
|
+ */
|
|
|
+ public void activateBySession(java.util.Map<String, Object> userProperties) {
|
|
|
+ if (!saasEnabled) return;
|
|
|
+ Long tenantId = (Long) userProperties.get("_tenantId");
|
|
|
+ String dsKey = (String) userProperties.get("_dsKey");
|
|
|
+ if (tenantId == null || StringUtils.isBlank(dsKey)) return;
|
|
|
+ DynamicDataSourceContextHolder.setDataSourceType(dsKey);
|
|
|
+ SecurityContextHolder.getContext().setAuthentication(
|
|
|
+ new UsernamePasswordAuthenticationToken(
|
|
|
+ new TenantPrincipal(tenantId), null, Collections.emptyList()));
|
|
|
+ try {
|
|
|
+ SysConfig cfg = sysConfigMapper.selectConfigByConfigKey("projectConfig");
|
|
|
+ if (cfg != null && StringUtils.isNotBlank(cfg.getConfigValue())) {
|
|
|
+ TenantConfigContext.set(JSONObject.parseObject(cfg.getConfigValue()));
|
|
|
+ } else {
|
|
|
+ TenantConfigContext.set(null);
|
|
|
+ }
|
|
|
+ ProjectConfig.loadTenantConfigsFromContext();
|
|
|
+ } catch (Exception e) {
|
|
|
+ log.warn("[SaaS WS] 加载租户项目配置失败 tenantId={}", tenantId, e);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * javax.websocket 专用:根据 tenantCode 直接切换数据源 + SecurityContext。
|
|
|
+ * 与 bindTenant(Channel) 不同,此方法每次调用都会查库并激活,无需提前绑定到 Channel。
|
|
|
+ * 若未启用 SaaS 或 tenantCode 为空,不做任何处理。
|
|
|
+ * @deprecated 改用 resolveAndStore + activateBySession 避免每次查库
|
|
|
+ */
|
|
|
+ public void bindTenantByCode(String tenantCode) {
|
|
|
+ if (!saasEnabled || StringUtils.isBlank(tenantCode)) return;
|
|
|
+ try {
|
|
|
+ DynamicDataSourceContextHolder.setDataSourceType(DataSourceType.MASTER.name());
|
|
|
+ TenantInfo query = new TenantInfo();
|
|
|
+ query.setTenantCode(tenantCode);
|
|
|
+ List<TenantInfo> list = tenantInfoService.selectTenantInfoList(query);
|
|
|
+ if (list == null || list.isEmpty()) {
|
|
|
+ log.warn("[SaaS WS] bindTenantByCode: tenantCode={} 未找到租户", tenantCode);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ TenantInfo tenant = list.get(0);
|
|
|
+ if (!Integer.valueOf(1).equals(tenant.getStatus())) return;
|
|
|
+ if (tenant.getExpireTime() != null && tenant.getExpireTime().before(new Date())) return;
|
|
|
+ tenantDataSourceManager.switchTenant(tenant);
|
|
|
+ String dsKey = "tenant:" + tenant.getId();
|
|
|
+ DynamicDataSourceContextHolder.setDataSourceType(dsKey);
|
|
|
+ SecurityContextHolder.getContext().setAuthentication(
|
|
|
+ new UsernamePasswordAuthenticationToken(
|
|
|
+ new TenantPrincipal(tenant.getId()), null, Collections.emptyList()));
|
|
|
+ try {
|
|
|
+ SysConfig cfg = sysConfigMapper.selectConfigByConfigKey("projectConfig");
|
|
|
+ if (cfg != null && StringUtils.isNotBlank(cfg.getConfigValue())) {
|
|
|
+ TenantConfigContext.set(JSONObject.parseObject(cfg.getConfigValue()));
|
|
|
+ } else {
|
|
|
+ TenantConfigContext.set(null);
|
|
|
+ }
|
|
|
+ ProjectConfig.loadTenantConfigsFromContext();
|
|
|
+ } catch (Exception e) {
|
|
|
+ log.warn("[SaaS WS] 加载租户项目配置失败 tenantId={}", tenant.getId(), e);
|
|
|
+ }
|
|
|
+ } catch (Exception e) {
|
|
|
+ log.error("[SaaS WS] bindTenantByCode 失败 tenantCode={}", tenantCode, e);
|
|
|
+ DynamicDataSourceContextHolder.clearDataSourceType();
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|