diff --git a/pom.xml b/pom.xml
index 67309a22..1642e808 100644
--- a/pom.xml
+++ b/pom.xml
@@ -243,6 +243,19 @@
1.0.0
+
+ wzy
+
+ dev
+
+ 172.16.46.63:30848
+ wzy
+ DEFAULT_GROUP
+ nacos
+ P@ssword25
+ 1.0.0
+
+
klw-dev
diff --git a/zt-module-databus/zt-module-databus-server-app/src/main/resources/application-dev.yml b/zt-module-databus/zt-module-databus-server-app/src/main/resources/application-dev.yml
index f7189ad3..0428df40 100644
--- a/zt-module-databus/zt-module-databus-server-app/src/main/resources/application-dev.yml
+++ b/zt-module-databus/zt-module-databus-server-app/src/main/resources/application-dev.yml
@@ -37,17 +37,11 @@ spring:
primary: master
datasource:
master:
- #url: jdbc:dm://172.16.46.247:1050?schema=RUOYI-VUE-PRO
- #username: SYSDBA
- #password: pgbsci6ddJ6Sqj@e
url: jdbc:dm://172.17.11.98:20870?schema=JYGK_TEST
username: SYSDBA
password: P@ssword25
slave: # 模拟从库,可根据自己需要修改 # 模拟从库,可根据自己需要修改
lazy: true # 开启懒加载,保证启动速度
- #url: jdbc:dm://172.16.46.247:1050?schema=RUOYI-VUE-PRO
- #username: SYSDBA
- #password: pgbsci6ddJ6Sqj@e
url: jdbc:dm://172.17.11.98:20870?schema=JYGK_TEST
username: SYSDBA
password: P@ssword25
@@ -58,8 +52,9 @@ spring:
host: 172.16.46.63 # 地址
port: 30379 # 端口
database: 0 # 数据库索引
- username: zt-redis # 密码,建议生产环境开启
+ username: zt-redis
password: P@ssword25
+# password: 123456 # 密码,建议生产环境开启
xxl:
job:
diff --git a/zt-module-databus/zt-module-databus-server/src/main/java/com/zt/plat/module/databus/framework/integration/gateway/security/GatewaySecurityFilter.java b/zt-module-databus/zt-module-databus-server/src/main/java/com/zt/plat/module/databus/framework/integration/gateway/security/GatewaySecurityFilter.java
index b37dfb76..7bd4e98f 100644
--- a/zt-module-databus/zt-module-databus-server/src/main/java/com/zt/plat/module/databus/framework/integration/gateway/security/GatewaySecurityFilter.java
+++ b/zt-module-databus/zt-module-databus-server/src/main/java/com/zt/plat/module/databus/framework/integration/gateway/security/GatewaySecurityFilter.java
@@ -108,7 +108,9 @@ public class GatewaySecurityFilter extends OncePerRequestFilter {
credential = credentialService.findActiveCredential(appId)
.orElseThrow(() -> new SecurityValidationException(HttpStatus.UNAUTHORIZED, "应用凭证不存在或已禁用"));
boolean allowAnonymous = Boolean.TRUE.equals(credential.getAllowAnonymous());
+ boolean enableEncryption = Boolean.TRUE.equals(credential.getEnableEncryption());
ApiAnonymousUserService.AnonymousUserDetails anonymousDetails = null;
+ byte[] requestBody = StreamUtils.copyToByteArray(request.getInputStream());
if (allowAnonymous) {
Long anonymousUserId = credential.getAnonymousUserId();
if (anonymousUserId == null) {
@@ -117,24 +119,25 @@ public class GatewaySecurityFilter extends OncePerRequestFilter {
anonymousDetails = anonymousUserService.find(anonymousUserId)
.orElseThrow(() -> new SecurityValidationException(HttpStatus.UNAUTHORIZED, "匿名访问固定用户不可用"));
}
-
String timestampHeader = requireHeader(request, TIMESTAMP_HEADER, "缺少时间戳");
// 校验时间戳与随机数,防止请求被重放
validateTimestamp(timestampHeader, security);
- String nonce = requireHeader(request, NONCE_HEADER, "缺少随机数");
- if (nonce.length() < 8) {
- throw new SecurityValidationException(HttpStatus.BAD_REQUEST, "随机数长度不足");
- }
- String signature = requireHeader(request, SIGNATURE_HEADER, "缺少签名");
+ if (enableEncryption){
+ String nonce = requireHeader(request, NONCE_HEADER, "缺少随机数");
+ if (nonce.length() < 8) {
+ throw new SecurityValidationException(HttpStatus.BAD_REQUEST, "随机数长度不足");
+ }
+ String signature = requireHeader(request, SIGNATURE_HEADER, "缺少签名");
- byte[] originalBody = StreamUtils.copyToByteArray(request.getInputStream());
- // 尝试按凭证配置解密请求体,并构建签名载荷进行校验
- byte[] decryptedBody = decryptRequestBody(originalBody, credential, security);
- verifySignature(request, decryptedBody, signature, credential, security, appId, timestampHeader);
- ensureNonce(tenantId, appId, nonce, security);
+ // 尝试按凭证配置解密请求体,并构建签名载荷进行校验
+ byte[] decryptedBody = decryptRequestBody(requestBody, credential, security);
+ verifySignature(request, decryptedBody, signature, credential, security, appId, timestampHeader);
+ ensureNonce(tenantId, appId, nonce, security);
+ requestBody = decryptedBody;
+ }
// 使用可重复读取的请求包装,供后续过滤器继续消费
- CachedBodyHttpServletRequest securedRequest = new CachedBodyHttpServletRequest(request, decryptedBody);
+ CachedBodyHttpServletRequest securedRequest = new CachedBodyHttpServletRequest(request, requestBody);
securedRequest.setHeader(APP_ID_HEADER, credential.getAppId());
securedRequest.setHeader(HEADER_CREDENTIAL_ID, credential.getId() != null ? String.valueOf(credential.getId()) : null);
ApiGatewayAccessLogger.propagateLogIdHeader(securedRequest, accessLogId);
diff --git a/zt-module-system/zt-module-system-api/src/main/java/com/zt/plat/module/system/api/user/dto/AdminUserRespDTO.java b/zt-module-system/zt-module-system-api/src/main/java/com/zt/plat/module/system/api/user/dto/AdminUserRespDTO.java
index 60fada58..57bec45e 100644
--- a/zt-module-system/zt-module-system-api/src/main/java/com/zt/plat/module/system/api/user/dto/AdminUserRespDTO.java
+++ b/zt-module-system/zt-module-system-api/src/main/java/com/zt/plat/module/system/api/user/dto/AdminUserRespDTO.java
@@ -4,6 +4,7 @@ import com.fhs.core.trans.vo.VO;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
+import java.time.LocalDateTime;
import java.util.List;
import java.util.Set;
@@ -20,6 +21,12 @@ public class AdminUserRespDTO implements VO {
@Schema(description = "用户昵称", requiredMode = Schema.RequiredMode.REQUIRED, example = "小王")
private String nickname;
+ @Schema(description = "工号", example = "A00123")
+ private String workcode;
+
+ @Schema(description = "备注", example = "我是一个用户")
+ private String remark;
+
@Schema(description = "租户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
private Long tenantId;
diff --git a/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/service/integration/iwork/impl/IWorkSyncProcessorImpl.java b/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/service/integration/iwork/impl/IWorkSyncProcessorImpl.java
index 0d44b790..5547d727 100644
--- a/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/service/integration/iwork/impl/IWorkSyncProcessorImpl.java
+++ b/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/service/integration/iwork/impl/IWorkSyncProcessorImpl.java
@@ -28,7 +28,10 @@ import com.zt.plat.module.system.util.sync.SyncVerifyUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
+import org.springframework.util.DigestUtils;
+import java.nio.charset.StandardCharsets;
+import java.util.Locale;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
@@ -39,6 +42,8 @@ public class IWorkSyncProcessorImpl implements IWorkSyncProcessor {
private static final String JOB_CODE_PREFIX = "IWORK_JOB_";
private static final int DEFAULT_SORT = 999;
+ /** 当上游密码缺失时,用空字符串的 MD5 作为占位,保证账号可创建 */
+ private static final String EMPTY_PASSWORD_PLACEHOLDER = DigestUtils.md5DigestAsHex("".getBytes(StandardCharsets.UTF_8)).toUpperCase(Locale.ROOT);
private final DeptService deptService;
private final PostService postService;
@@ -326,9 +331,8 @@ public class IWorkSyncProcessorImpl implements IWorkSyncProcessor {
boolean inactive = isInactiveUser(user.getStatus());
String username = resolveUsername(user);
if (StrUtil.isBlank(username)) {
- log.warn("[iWork] 人员缺少可用账号(工号={}, 登录账号={}),跳过:id={} name={}",
- user.getWorkcode(), user.getLoginid(), user.getId(), user.getLastname());
- result.increaseFailed();
+ logSkip("人员", user.getId(), "缺少工号与登录账号,跳过同步");
+ result.increaseSkipped();
continue;
}
try {
@@ -350,9 +354,8 @@ public class IWorkSyncProcessorImpl implements IWorkSyncProcessor {
continue;
}
if (StrUtil.isBlank(externalPassword)) {
- log.warn("[iWork] 人员缺少密码信息,无法创建:id={} username={}", user.getId(), username);
- result.increaseFailed();
- continue;
+ externalPassword = EMPTY_PASSWORD_PLACEHOLDER;
+ log.info("[iWork] 人员缺少密码信息,使用空密码占位同步:id={} username={}", user.getId(), username);
}
outcome = createUser(user, username, deptId, postId, status, externalPassword);
} else {
@@ -545,7 +548,7 @@ public class IWorkSyncProcessorImpl implements IWorkSyncProcessor {
CommonStatusEnum status) {
UserSaveReqVO req = new UserSaveReqVO();
req.setUsername(username);
- req.setWorkcode(trimToNull(source.getWorkcode()));
+ req.setWorkcode(resolveWorkcode(source));
req.setNickname(limitLength(StrUtil.blankToDefault(source.getLastname(), username), 30));
req.setRemark(buildUserRemark(source));
if (deptId != null) {
@@ -776,6 +779,26 @@ public class IWorkSyncProcessorImpl implements IWorkSyncProcessor {
* 工号优先、登录账号兜底,确保账号体系与 iWork 一致
*/
private String resolveUsername(IWorkHrUserPageRespVO.User user) {
+ if (user == null) {
+ return null;
+ }
+ String workcode = resolveWorkcode(user);
+ if (StrUtil.isNotBlank(workcode)) {
+ return workcode;
+ }
+ if (StrUtil.isNotBlank(user.getLoginid())) {
+ return user.getLoginid().trim();
+ }
+ return null;
+ }
+
+ /**
+ * 工号为空时自动使用登录账号作为工号兜底,避免因缺失工号而跳过同步。
+ */
+ private String resolveWorkcode(IWorkHrUserPageRespVO.User user) {
+ if (user == null) {
+ return null;
+ }
if (StrUtil.isNotBlank(user.getWorkcode())) {
return user.getWorkcode().trim();
}