feat(license): license 文件新增 serverUrl 字段,私有化部署自动写入

私有化模式下生成的 license 文件包含 serverUrl,SDK 通过
XuqmSDK.autoInitialize() 读取后可自动配置所有服务端点,
无需在 App 层硬编码 appKey 或 serverUrl。

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
这个提交包含在:
XuqmGroup 2026-05-21 15:25:13 +08:00
父节点 a98dbca26d
当前提交 cc132c7ce7

查看文件

@ -12,6 +12,7 @@ import com.xuqm.tenant.service.AppUserClient;
import com.xuqm.tenant.service.EmailService; import com.xuqm.tenant.service.EmailService;
import com.xuqm.tenant.service.FeatureServiceManager; import com.xuqm.tenant.service.FeatureServiceManager;
import com.xuqm.tenant.service.LicenseFileCrypto; import com.xuqm.tenant.service.LicenseFileCrypto;
import com.xuqm.tenant.config.PrivateDeploymentProperties;
import com.xuqm.tenant.service.OperationLogService; import com.xuqm.tenant.service.OperationLogService;
import jakarta.validation.Valid; import jakarta.validation.Valid;
import org.springframework.beans.factory.annotation.Value; import org.springframework.beans.factory.annotation.Value;
@ -43,6 +44,7 @@ public class AppController {
private final TenantRepository tenantRepository; private final TenantRepository tenantRepository;
private final FeatureServiceManager featureServiceManager; private final FeatureServiceManager featureServiceManager;
private final AppUserClient appUserClient; private final AppUserClient appUserClient;
private final PrivateDeploymentProperties deployProps;
@Value("${license.public-base-url:https://auth.dev.xuqinmin.com/}") @Value("${license.public-base-url:https://auth.dev.xuqinmin.com/}")
private String licensePublicBaseUrl; private String licensePublicBaseUrl;
@ -51,13 +53,15 @@ public class AppController {
OperationLogService operationLogService, OperationLogService operationLogService,
TenantRepository tenantRepository, TenantRepository tenantRepository,
FeatureServiceManager featureServiceManager, FeatureServiceManager featureServiceManager,
AppUserClient appUserClient) { AppUserClient appUserClient,
PrivateDeploymentProperties deployProps) {
this.appService = appService; this.appService = appService;
this.emailService = emailService; this.emailService = emailService;
this.operationLogService = operationLogService; this.operationLogService = operationLogService;
this.tenantRepository = tenantRepository; this.tenantRepository = tenantRepository;
this.featureServiceManager = featureServiceManager; this.featureServiceManager = featureServiceManager;
this.appUserClient = appUserClient; this.appUserClient = appUserClient;
this.deployProps = deployProps;
} }
@GetMapping @GetMapping
@ -178,6 +182,11 @@ public class AppController {
payload.put("appName", app.getName()); payload.put("appName", app.getName());
payload.put("packageName", app.getPackageName()); payload.put("packageName", app.getPackageName());
payload.put("baseUrl", normalizeBaseUrl(licensePublicBaseUrl)); payload.put("baseUrl", normalizeBaseUrl(licensePublicBaseUrl));
// serverUrl is set only for private deployments; the SDK uses it to configure all service
// endpoints automatically via XuqmSDK.autoInitialize(). Public deployments use default endpoints.
if (deployProps.isPrivate()) {
payload.put("serverUrl", normalizeBaseUrl(licensePublicBaseUrl));
}
payload.put("issuedAt", java.time.Instant.now().toString()); payload.put("issuedAt", java.time.Instant.now().toString());
String encrypted = LicenseFileCrypto.encrypt(new com.fasterxml.jackson.databind.ObjectMapper().valueToTree(payload).toString()); String encrypted = LicenseFileCrypto.encrypt(new com.fasterxml.jackson.databind.ObjectMapper().valueToTree(payload).toString());
String filename = sanitizeFileName(app.getName()) + ".xuqmlicense"; String filename = sanitizeFileName(app.getName()) + ".xuqmlicense";