From 9e98fa8c23d2e7cdd9848f7b603eb57bedc1aa87 Mon Sep 17 00:00:00 2001 From: chenbowen Date: Thu, 29 Jan 2026 14:51:32 +0800 Subject: [PATCH] =?UTF-8?q?=E9=87=8D=E5=86=99=E6=89=8B=E5=8A=A8=E9=92=88?= =?UTF-8?q?=E5=AF=B9=E7=94=A8=E6=88=B7=E4=BB=A5=E5=8F=8A=E7=BB=84=E7=BB=87?= =?UTF-8?q?=E7=9A=84=E5=8D=95=E6=9D=A1=E5=90=8C=E6=AD=A5=E9=80=BB=E8=BE=91?= =?UTF-8?q?=20=E7=99=BB=E5=BD=95=E8=8E=B7=E5=8F=96=20token=20=E6=97=B6?= =?UTF-8?q?=E6=96=B0=E5=A2=9E=E5=AE=A2=E6=88=B7=E7=AB=AF=E7=BC=96=E5=8F=B7?= =?UTF-8?q?=E6=A0=87=E8=AF=86=20=E6=94=AF=E6=8C=81=E6=A0=B9=E6=8D=AE?= =?UTF-8?q?=E5=AE=A2=E6=88=B7=E7=AB=AF=E7=BC=96=E5=8F=B7=E4=BB=A5=E5=8F=8A?= =?UTF-8?q?=E7=94=A8=E6=88=B7id=E6=89=B9=E9=87=8F=E5=A4=B1=E6=95=88=20toke?= =?UTF-8?q?n=20=E6=96=B9=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../system/oauth2/OAuth2TokenCommonApi.java | 9 + .../system/api/oauth2/OAuth2TokenApiImpl.java | 5 + .../admin/auth/vo/AuthLoginReqVO.java | 3 + .../admin/auth/vo/AuthSmsLoginReqVO.java | 3 + .../admin/auth/vo/AuthSocialLoginReqVO.java | 3 + .../admin/auth/vo/AuthTestLoginReqVO.java | 3 + .../iwork/IWorkIntegrationController.java | 41 +++- .../iwork/vo/IWorkSyncByIdReqVO.java | 84 -------- .../mysql/oauth2/OAuth2AccessTokenMapper.java | 6 + .../oauth2/OAuth2RefreshTokenMapper.java | 6 + .../service/auth/AdminAuthServiceImpl.java | 21 +- .../integration/iwork/IWorkSyncService.java | 7 - .../iwork/impl/IWorkSyncServiceImpl.java | 201 ------------------ .../service/oauth2/OAuth2TokenService.java | 10 + .../oauth2/OAuth2TokenServiceImpl.java | 12 ++ 15 files changed, 109 insertions(+), 305 deletions(-) diff --git a/zt-framework/zt-common/src/main/java/com/zt/plat/framework/common/biz/system/oauth2/OAuth2TokenCommonApi.java b/zt-framework/zt-common/src/main/java/com/zt/plat/framework/common/biz/system/oauth2/OAuth2TokenCommonApi.java index 4e3bef56..2ad34826 100644 --- a/zt-framework/zt-common/src/main/java/com/zt/plat/framework/common/biz/system/oauth2/OAuth2TokenCommonApi.java +++ b/zt-framework/zt-common/src/main/java/com/zt/plat/framework/common/biz/system/oauth2/OAuth2TokenCommonApi.java @@ -49,4 +49,13 @@ public interface OAuth2TokenCommonApi { CommonResult refreshAccessToken(@RequestParam("refreshToken") String refreshToken, @RequestParam("clientId") String clientId); + @DeleteMapping(PREFIX + "/remove-by-user") + @Operation(summary = "按 userId + clientId 失效访问令牌") + @Parameters({ + @Parameter(name = "userId", description = "用户编号", required = true, example = "1"), + @Parameter(name = "clientId", description = "客户端编号", required = true, example = "default") + }) + CommonResult removeAccessTokensByUserIdAndClientId(@RequestParam("userId") Long userId, + @RequestParam("clientId") String clientId); + } diff --git a/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/api/oauth2/OAuth2TokenApiImpl.java b/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/api/oauth2/OAuth2TokenApiImpl.java index 82626b53..70af3f9f 100644 --- a/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/api/oauth2/OAuth2TokenApiImpl.java +++ b/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/api/oauth2/OAuth2TokenApiImpl.java @@ -48,4 +48,9 @@ public class OAuth2TokenApiImpl implements OAuth2TokenCommonApi { return success(BeanUtils.toBean(accessTokenDO, OAuth2AccessTokenRespDTO.class)); } + @Override + public CommonResult removeAccessTokensByUserIdAndClientId(Long userId, String clientId) { + return success(oauth2TokenService.removeAccessTokensByUserIdAndClientId(userId, clientId)); + } + } diff --git a/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/controller/admin/auth/vo/AuthLoginReqVO.java b/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/controller/admin/auth/vo/AuthLoginReqVO.java index 61d840cf..c3fc0260 100644 --- a/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/controller/admin/auth/vo/AuthLoginReqVO.java +++ b/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/controller/admin/auth/vo/AuthLoginReqVO.java @@ -30,6 +30,9 @@ public class AuthLoginReqVO extends CaptchaVerificationReqVO { // @Length(min = 4, max = 16, message = "密码长度为 4-16 位") private String password; + @Schema(description = "客户端编号", requiredMode = Schema.RequiredMode.NOT_REQUIRED, example = "default") + private String clientId; + // ========== 绑定社交登录时,需要传递如下参数 ========== @Schema(description = "社交平台的类型,参见 SocialTypeEnum 枚举值", requiredMode = Schema.RequiredMode.REQUIRED, example = "10") diff --git a/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/controller/admin/auth/vo/AuthSmsLoginReqVO.java b/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/controller/admin/auth/vo/AuthSmsLoginReqVO.java index dabe6025..d7945584 100644 --- a/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/controller/admin/auth/vo/AuthSmsLoginReqVO.java +++ b/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/controller/admin/auth/vo/AuthSmsLoginReqVO.java @@ -24,4 +24,7 @@ public class AuthSmsLoginReqVO { @NotEmpty(message = "验证码不能为空") private String code; + @Schema(description = "客户端编号", requiredMode = Schema.RequiredMode.NOT_REQUIRED, example = "default") + private String clientId; + } diff --git a/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/controller/admin/auth/vo/AuthSocialLoginReqVO.java b/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/controller/admin/auth/vo/AuthSocialLoginReqVO.java index bfdcb040..e656f4f5 100644 --- a/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/controller/admin/auth/vo/AuthSocialLoginReqVO.java +++ b/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/controller/admin/auth/vo/AuthSocialLoginReqVO.java @@ -30,4 +30,7 @@ public class AuthSocialLoginReqVO { @NotEmpty(message = "state 不能为空") private String state; + @Schema(description = "客户端编号", requiredMode = Schema.RequiredMode.NOT_REQUIRED, example = "default") + private String clientId; + } diff --git a/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/controller/admin/auth/vo/AuthTestLoginReqVO.java b/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/controller/admin/auth/vo/AuthTestLoginReqVO.java index b43587ee..ef2f29ae 100644 --- a/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/controller/admin/auth/vo/AuthTestLoginReqVO.java +++ b/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/controller/admin/auth/vo/AuthTestLoginReqVO.java @@ -26,4 +26,7 @@ public class AuthTestLoginReqVO { @Length(min = 4, max = 16, message = "密码长度为 4-16 位") private String password; + @Schema(description = "客户端编号", requiredMode = Schema.RequiredMode.NOT_REQUIRED, example = "default") + private String clientId; + } \ No newline at end of file diff --git a/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/controller/admin/integration/iwork/IWorkIntegrationController.java b/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/controller/admin/integration/iwork/IWorkIntegrationController.java index f3b6f08a..e5262fa2 100644 --- a/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/controller/admin/integration/iwork/IWorkIntegrationController.java +++ b/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/controller/admin/integration/iwork/IWorkIntegrationController.java @@ -176,16 +176,43 @@ public class IWorkIntegrationController { return success(syncService.fullSyncUsers(reqVO)); } - // ----------------- 根据ID同步到本地 ----------------- + // ----------------- 根据ID同步到本地(仅传 ID) ----------------- - @PostMapping("/syncById") - @Operation(summary = "根据ID触发 iWork 同步公司") - public CommonResult syncById(@Valid @RequestBody IWorkSyncByIdReqVO reqVO) { - - log.error("IWork集成后端手动录入syncById{}",reqVO); - return success(syncService.manuallySyncData(reqVO)); + @PostMapping("/sync/user-by-id") + @Operation(summary = "根据ID同步 iWork 人员(单条)") + public CommonResult syncUserById(@Valid @RequestBody IWorkSyncByIdReqVO reqVO) { + IWorkFullSyncReqVO fullReq = new IWorkFullSyncReqVO(); + fullReq.setId(reqVO.getId()); + fullReq.setStartPage(1); + fullReq.setPageSize(1); + fullReq.setMaxPages(1); + fullReq.setAllowUpdate(Boolean.TRUE); + return success(syncService.fullSyncUsers(fullReq)); } + @PostMapping("/sync/department-by-id") + @Operation(summary = "根据ID同步 iWork 部门(单条)") + public CommonResult syncDepartmentById(@Valid @RequestBody IWorkSyncByIdReqVO reqVO) { + IWorkFullSyncReqVO fullReq = new IWorkFullSyncReqVO(); + fullReq.setId(reqVO.getId()); + fullReq.setStartPage(1); + fullReq.setPageSize(1); + fullReq.setMaxPages(1); + fullReq.setAllowUpdate(Boolean.TRUE); + return success(syncService.fullSyncDepartments(fullReq)); + } + + @PostMapping("/sync/subcompany-by-id") + @Operation(summary = "根据ID同步 iWork 分部(单条)") + public CommonResult syncSubcompanyById(@Valid @RequestBody IWorkSyncByIdReqVO reqVO) { + IWorkFullSyncReqVO fullReq = new IWorkFullSyncReqVO(); + fullReq.setId(reqVO.getId()); + fullReq.setStartPage(1); + fullReq.setPageSize(1); + fullReq.setMaxPages(1); + fullReq.setAllowUpdate(Boolean.TRUE); + return success(syncService.fullSyncSubcompanies(fullReq)); + } private ResponseEntity buildOaResponse(IWorkOaRawResponse resp) { if (resp == null) { diff --git a/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/controller/admin/integration/iwork/vo/IWorkSyncByIdReqVO.java b/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/controller/admin/integration/iwork/vo/IWorkSyncByIdReqVO.java index c91a3f66..bfed644d 100644 --- a/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/controller/admin/integration/iwork/vo/IWorkSyncByIdReqVO.java +++ b/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/controller/admin/integration/iwork/vo/IWorkSyncByIdReqVO.java @@ -1,99 +1,15 @@ package com.zt.plat.module.system.controller.admin.integration.iwork.vo; -import com.zt.plat.module.system.enums.integration.IWorkSyncEntityTypeEnum; import io.swagger.v3.oas.annotations.media.Schema; -import jakarta.validation.constraints.Max; -import jakarta.validation.constraints.Min; import jakarta.validation.constraints.NotBlank; import lombok.Data; -import java.util.EnumSet; -import java.util.List; -import java.util.Set; -import java.util.stream.Collectors; - /** * iWork 手动同步请求 */ @Data public class IWorkSyncByIdReqVO { - - - @Schema(description = "起始页码,从 1 开始", example = "1") - @Min(1) - private Integer startPage = 1; - - @Schema(description = "最大处理页数,null 表示处理至 iWork 返回的末页", example = "10") - @Min(1) - private Integer maxPages; - - @Schema(description = "每次分页从 iWork 拉取的记录数", example = "100") - @Min(1) - @Max(500) - private Integer pageSize = 100; - - @Schema(description = "同步范围列表,默认同步全部。可选:subcompany、department、jobTitle、user") - private List scopes; - - @Schema(description = "是否包含已失效(canceled=1)的记录", example = "false") - private Boolean includeCanceled = Boolean.FALSE; - - @Schema(description = "是否允许更新已存在的本地实体", example = "false") - private Boolean allowUpdate = Boolean.FALSE; - - @Schema(description = "指定同步记录的 iWork ID。传入后仅同步对应记录", example = "12345") @NotBlank(message = "ID不能为空") private String id; - - @Schema(description = "部门编码", example = "ZT001") - private String code; - - @Schema(description = "部门名称", example = "ZT") - private String name; - - @Schema(description = "部门简称", example = "技术") - private String shortName; - - @Schema(description = "父部门 ID", example = "1024") - private String parentId; - - @Schema(description = "负责人的用户编号", example = "2048") - private String leaderUserId; - - @Schema(description = "联系电话", example = "15601691000") - private String phone; - - @Schema(description = "邮箱", example = "zt@iocoder.cn") - private String email; - - @Schema(description = "状态,见 CommonStatusEnum 枚举0 开启 1 关闭", example = "0") - private Integer status; - - private Long tenantId; - - @Schema(description = "是否公司", example = "false") - private boolean isCompany; - - @Schema(description = "是否集团", example = "false") - private boolean isGroup; - - private boolean hasChildren; - - - public Set resolveScopes() { - EnumSet defaults = EnumSet.allOf(IWorkSyncEntityTypeEnum.class); - if (scopes == null || scopes.isEmpty()) { - return defaults; - } - Set resolved = scopes.stream() - .map(IWorkSyncEntityTypeEnum::fromCode) - .filter(java.util.Objects::nonNull) - .collect(Collectors.toCollection(() -> EnumSet.noneOf(IWorkSyncEntityTypeEnum.class))); - if (resolved.isEmpty()) { - return defaults; - } - return resolved; - } - } diff --git a/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/dal/mysql/oauth2/OAuth2AccessTokenMapper.java b/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/dal/mysql/oauth2/OAuth2AccessTokenMapper.java index e3b982fe..78e50736 100644 --- a/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/dal/mysql/oauth2/OAuth2AccessTokenMapper.java +++ b/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/dal/mysql/oauth2/OAuth2AccessTokenMapper.java @@ -31,6 +31,12 @@ public interface OAuth2AccessTokenMapper extends BaseMapperX selectListByUserIdAndClientId(Long userId, String clientId) { + return selectList(new LambdaQueryWrapperX() + .eq(OAuth2AccessTokenDO::getUserId, userId) + .eq(OAuth2AccessTokenDO::getClientId, clientId)); + } + default List selectListByRefreshToken(String refreshToken) { return selectList(OAuth2AccessTokenDO::getRefreshToken, refreshToken); } diff --git a/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/dal/mysql/oauth2/OAuth2RefreshTokenMapper.java b/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/dal/mysql/oauth2/OAuth2RefreshTokenMapper.java index 5bc32f58..1aa6cbf4 100644 --- a/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/dal/mysql/oauth2/OAuth2RefreshTokenMapper.java +++ b/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/dal/mysql/oauth2/OAuth2RefreshTokenMapper.java @@ -19,4 +19,10 @@ public interface OAuth2RefreshTokenMapper extends BaseMapperX() + .eq(OAuth2RefreshTokenDO::getUserId, userId) + .eq(OAuth2RefreshTokenDO::getClientId, clientId)); + } + } diff --git a/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/service/auth/AdminAuthServiceImpl.java b/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/service/auth/AdminAuthServiceImpl.java index d7e43355..fa79ea6e 100644 --- a/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/service/auth/AdminAuthServiceImpl.java +++ b/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/service/auth/AdminAuthServiceImpl.java @@ -149,7 +149,7 @@ public class AdminAuthServiceImpl implements AdminAuthService { reqVO.getSocialType(), reqVO.getSocialCode(), reqVO.getSocialState())); } // 创建 Token 令牌,记录登录日志 - return createTokenAfterLoginSuccess(user.getId(), reqVO.getUsername(), LoginLogTypeEnum.LOGIN_USERNAME); + return createTokenAfterLoginSuccess(user.getId(), reqVO.getUsername(), LoginLogTypeEnum.LOGIN_USERNAME, reqVO.getClientId()); } @Override @@ -167,7 +167,7 @@ public class AdminAuthServiceImpl implements AdminAuthService { } // 创建 Token 令牌,记录登录日志 - return createTokenAfterLoginSuccess(user.getId(), reqVO.getUsername(), LoginLogTypeEnum.LOGIN_USERNAME); + return createTokenAfterLoginSuccess(user.getId(), reqVO.getUsername(), LoginLogTypeEnum.LOGIN_USERNAME, reqVO.getClientId()); } @Override @@ -200,7 +200,7 @@ public class AdminAuthServiceImpl implements AdminAuthService { } // 创建 Token 令牌,记录登录日志 - return createTokenAfterLoginSuccess(user.getId(), reqVO.getMobile(), LoginLogTypeEnum.LOGIN_MOBILE); + return createTokenAfterLoginSuccess(user.getId(), reqVO.getMobile(), LoginLogTypeEnum.LOGIN_MOBILE, reqVO.getClientId()); } private void createLoginLog(Long userId, String username, @@ -238,7 +238,7 @@ public class AdminAuthServiceImpl implements AdminAuthService { } // 创建 Token 令牌,记录登录日志 - return createTokenAfterLoginSuccess(user.getId(), user.getUsername(), LoginLogTypeEnum.LOGIN_SOCIAL); + return createTokenAfterLoginSuccess(user.getId(), user.getUsername(), LoginLogTypeEnum.LOGIN_SOCIAL, reqVO.getClientId()); } @VisibleForTesting @@ -267,16 +267,25 @@ public class AdminAuthServiceImpl implements AdminAuthService { return captchaService.verification(captchaVO); } - private AuthLoginRespVO createTokenAfterLoginSuccess(Long userId, String username, LoginLogTypeEnum logType) { + private AuthLoginRespVO createTokenAfterLoginSuccess(Long userId, String username, LoginLogTypeEnum logType, + String clientId) { // 插入登陆日志 createLoginLog(userId, username, logType, LoginResultEnum.SUCCESS); // 创建访问令牌 OAuth2AccessTokenDO accessTokenDO = oauth2TokenService.createAccessToken(userId, getUserType().getValue(), - OAuth2ClientConstants.CLIENT_ID_DEFAULT, null); + resolveClientId(clientId), null); // 构建返回结果 return AuthConvert.INSTANCE.convert(accessTokenDO); } + private AuthLoginRespVO createTokenAfterLoginSuccess(Long userId, String username, LoginLogTypeEnum logType) { + return createTokenAfterLoginSuccess(userId, username, logType, OAuth2ClientConstants.CLIENT_ID_DEFAULT); + } + + private String resolveClientId(String clientId) { + return StringUtils.isBlank(clientId) ? OAuth2ClientConstants.CLIENT_ID_DEFAULT : clientId; + } + @Override public AuthLoginRespVO refreshToken(String refreshToken) { OAuth2AccessTokenDO accessTokenDO = oauth2TokenService.refreshAccessToken(refreshToken, OAuth2ClientConstants.CLIENT_ID_DEFAULT); diff --git a/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/service/integration/iwork/IWorkSyncService.java b/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/service/integration/iwork/IWorkSyncService.java index c39dbaf6..47c70b70 100644 --- a/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/service/integration/iwork/IWorkSyncService.java +++ b/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/service/integration/iwork/IWorkSyncService.java @@ -2,9 +2,6 @@ package com.zt.plat.module.system.service.integration.iwork; import com.zt.plat.module.system.controller.admin.integration.iwork.vo.IWorkFullSyncReqVO; import com.zt.plat.module.system.controller.admin.integration.iwork.vo.IWorkFullSyncRespVO; -import com.zt.plat.module.system.controller.admin.integration.iwork.vo.IWorkSyncByIdReqVO; -import jakarta.validation.Valid; -import java.util.List; /** * iWork 组织/人员同步服务 @@ -31,8 +28,4 @@ public interface IWorkSyncService { */ IWorkFullSyncRespVO fullSyncUsers(IWorkFullSyncReqVO reqVO); - /** - * 手动同步 - */ - IWorkFullSyncRespVO manuallySyncData(@Valid IWorkSyncByIdReqVO list); } diff --git a/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/service/integration/iwork/impl/IWorkSyncServiceImpl.java b/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/service/integration/iwork/impl/IWorkSyncServiceImpl.java index dfb327a1..bc656b23 100644 --- a/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/service/integration/iwork/impl/IWorkSyncServiceImpl.java +++ b/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/service/integration/iwork/impl/IWorkSyncServiceImpl.java @@ -13,7 +13,6 @@ import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.BeanUtils; import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; import java.util.ArrayList; import java.util.EnumSet; @@ -66,15 +65,6 @@ public class IWorkSyncServiceImpl implements IWorkSyncService { return runFullSync(reqVO, EnumSet.of(IWorkSyncEntityTypeEnum.USER)); } - /** - * 手动同步 - */ - @Transactional - @Override - public IWorkFullSyncRespVO manuallySyncData(IWorkSyncByIdReqVO reqVO) { - return manuallySyncData(reqVO, EnumSet.of(IWorkSyncEntityTypeEnum.USER)); - } - /** * 全量同步方法 * @param reqVO 请求参数 @@ -299,100 +289,6 @@ public class IWorkSyncServiceImpl implements IWorkSyncService { private record BatchExecution(IWorkSyncProcessor.BatchResult result, int totalPulled) { } - - /** - * 根据ID同步 - */ - private IWorkFullSyncRespVO manuallySyncData(IWorkSyncByIdReqVO reqVO, Set scopes) { - - //1 初始化响应对象:创建响应VO并设置分页大小和批次统计列表 - IWorkFullSyncRespVO respVO = new IWorkFullSyncRespVO(); - List batchStats = new ArrayList<>(); - respVO.setBatches(batchStats); - //2 解析同步范围:根据传入的scopes确定需要同步的实体类型(用户、部门、分部、岗位) - boolean syncUsers = scopes.contains(IWorkSyncEntityTypeEnum.USER); - boolean syncDepartments = scopes.contains(IWorkSyncEntityTypeEnum.DEPARTMENT); - boolean syncSubcompanies = scopes.contains(IWorkSyncEntityTypeEnum.SUBCOMPANY); - boolean syncJobTitle = scopes.contains(IWorkSyncEntityTypeEnum.JOB_TITLE); - int processedPages = 0; - IWorkSyncProcessor.SyncOptions options = manualSync(reqVO); - IWorkSyncProcessor.DeptSyncContext deptSyncContext = (syncDepartments || syncSubcompanies) - ? new IWorkSyncProcessor.DeptSyncContext() - : null; - //3 按类型执行同步:依次执行分部、部门、岗位、用户的分页同步操作 - if (syncSubcompanies) { - processedPages += runManualFullSyncForSubsidiaries(reqVO, options, respVO.getSubcompanyStat(), batchStats, deptSyncContext);//分部统计信息 - } - if (syncDepartments) { - processedPages += departments(reqVO, options, respVO.getDepartmentStat(), batchStats, deptSyncContext);//部门统计信息 - } - if (syncJobTitle) { - processedPages += syncPositionsManually(reqVO, options, respVO.getJobTitleStat(), batchStats);//岗位统计信息 - } - if (syncUsers) { - processedPages += syncUsers(reqVO, options, respVO.getUserStat(), batchStats);//用户统计信息 - } - //4、处理部门上下文:对部门和分部同步进行特殊处理,包括刷新待处理数据和补全部门编码 - if (deptSyncContext != null) { - IWorkSyncProcessor.BatchResult flushResult = syncProcessor.flushDeptPending(deptSyncContext, options); - updateStat(respVO.getDepartmentStat(), flushResult, 0);//部门统计信息 - if (CollUtil.isNotEmpty(deptSyncContext.getPlaceholderDeptIds())) { - deptService.backfillMissingCodesWithoutEvent(deptSyncContext.getPlaceholderDeptIds()); - } - } - respVO.setProcessedPages(processedPages); - return respVO; - } - - - /** - * 手动同步 - */ - private IWorkSyncProcessor.SyncOptions manualSync(IWorkSyncByIdReqVO reqVO) { - boolean includeCanceled = Boolean.TRUE.equals(reqVO.getIncludeCanceled()); - boolean allowUpdate = Boolean.TRUE.equals(reqVO.getAllowUpdate()); - return IWorkSyncProcessor.SyncOptions.custom(includeCanceled, allowUpdate, true); - } - - - /** - * 手动执行子公司全量同步f - */ - private int runManualFullSyncForSubsidiaries(IWorkSyncByIdReqVO reqVO, - IWorkSyncProcessor.SyncOptions options, - IWorkSyncEntityStatVO stat, - List batches, - IWorkSyncProcessor.DeptSyncContext context) { - return paged(reqVO, IWorkSyncEntityTypeEnum.SUBCOMPANY, batches, (page, pageSize) -> { - IWorkSubcompanyQueryReqVO query = new IWorkSubcompanyQueryReqVO(); - query.setCurpage(page); - query.setPagesize(pageSize); - applyQuery(query, reqVO);//查询条件 - IWorkHrSubcompanyPageRespVO pageResp = orgRestService.listSubcompanies(query); - ensureIWorkSuccess("拉取分部", pageResp.isSuccess(), pageResp.getMessage());// IWork执行成功 - List dataList = CollUtil.emptyIfNull(pageResp.getDataList()); - IWorkSyncProcessor.BatchResult result = syncProcessor.syncSubcompanies(dataList, options, context); - updateStat(stat, result, dataList.size()); - return new BatchExecution(result, dataList.size()); - }); - } - - - /** - * 查询条件 - * @param query 查询条件 - * @param reqVO 请求 - */ - private void applyQuery(IWorkOrgBaseQueryReqVO query, IWorkSyncByIdReqVO reqVO) { - if (query == null || reqVO == null) { - return; - } - if (StrUtil.isBlank(reqVO.getId())) { - return; - } - applyQueryId(query, reqVO.getId()); - } - private void applyQueryId(IWorkOrgBaseQueryReqVO query, String id) { if (query == null || StrUtil.isBlank(id)) { return; @@ -413,101 +309,4 @@ public class IWorkSyncServiceImpl implements IWorkSyncService { userQuery.setId(id); } } - - - private int paged(IWorkSyncByIdReqVO reqVO, - IWorkSyncEntityTypeEnum type, - List batches, - PageExecutor executor) { - int startPage = reqVO.getStartPage() == null ? 1 : reqVO.getStartPage(); - int pageSize = reqVO.getPageSize() == null ? 100 : reqVO.getPageSize(); - int pagesLimit = reqVO.getMaxPages() == null ? Integer.MAX_VALUE : reqVO.getMaxPages(); - int processedPages = 0; - for (int page = startPage; processedPages < pagesLimit; page++) { - long pageStart = System.currentTimeMillis(); - BatchExecution execution = executor.execute(page, pageSize); - long pageMs = System.currentTimeMillis() - pageStart; - if (execution == null || execution.totalPulled == 0) { - break; - } - processedPages++; - log.info("[iWork] 手动同步 {} 页={} pulled={} costMs={}", type, page, execution.totalPulled, pageMs); - IWorkSyncBatchStatVO batchStat = new IWorkSyncBatchStatVO(); - batchStat.setEntityType(type); - batchStat.setPageNumber(page); - batchStat.setPulled(execution.totalPulled); - batchStat.setCreated(execution.result.getCreated()); - batchStat.setSkippedExisting(execution.result.getSkipped()); - batchStat.setDisabled(execution.result.getDisabled()); - batchStat.setFailed(execution.result.getFailed()); - batches.add(batchStat); - } - return processedPages; - } - - /** - * 手动执行部门同步 - */ - private int departments(IWorkSyncByIdReqVO reqVO, - IWorkSyncProcessor.SyncOptions options, - IWorkSyncEntityStatVO stat, - List batches, - IWorkSyncProcessor.DeptSyncContext context) { - return paged(reqVO, IWorkSyncEntityTypeEnum.DEPARTMENT, batches, (page, pageSize) -> { - IWorkDepartmentQueryReqVO query = new IWorkDepartmentQueryReqVO(); - query.setCurpage(page); - query.setPagesize(pageSize); - applyQuery(query, reqVO); - IWorkHrDepartmentPageRespVO pageResp = orgRestService.listDepartments(query); - ensureIWorkSuccess("拉取部门", pageResp.isSuccess(), pageResp.getMessage()); - List dataList = CollUtil.emptyIfNull(pageResp.getDataList()); - IWorkSyncProcessor.BatchResult result = syncProcessor.syncDepartments(dataList, options, context); - updateStat(stat, result, dataList.size()); - return new BatchExecution(result, dataList.size()); - }); - } - - - /** - * 手动执行岗位同步 - */ - private int syncPositionsManually(IWorkSyncByIdReqVO reqVO, - IWorkSyncProcessor.SyncOptions options, - IWorkSyncEntityStatVO stat, - List batches) { - return paged(reqVO, IWorkSyncEntityTypeEnum.JOB_TITLE, batches, (page, pageSize) -> { - IWorkJobTitleQueryReqVO query = new IWorkJobTitleQueryReqVO(); - query.setCurpage(page); - query.setPagesize(pageSize); - applyQuery(query, reqVO); - IWorkHrJobTitlePageRespVO pageResp = orgRestService.listJobTitles(query); - ensureIWorkSuccess("拉取岗位", pageResp.isSuccess(), pageResp.getMessage()); - List dataList = CollUtil.emptyIfNull(pageResp.getDataList()); - IWorkSyncProcessor.BatchResult result = syncProcessor.syncJobTitles(dataList, options); - updateStat(stat, result, dataList.size()); - return new BatchExecution(result, dataList.size()); - }); - } - - /** - * 手动执行用户同步 - */ - private int syncUsers(IWorkSyncByIdReqVO reqVO, - IWorkSyncProcessor.SyncOptions options, - IWorkSyncEntityStatVO stat, - List batches) { - return paged(reqVO, IWorkSyncEntityTypeEnum.USER, batches, (page, pageSize) -> { - IWorkUserQueryReqVO query = new IWorkUserQueryReqVO(); - query.setCurpage(page); - query.setPagesize(pageSize); - applyQuery(query, reqVO); - IWorkHrUserPageRespVO pageResp = orgRestService.listUsers(query); - ensureIWorkSuccess("拉取人员", pageResp.isSuccess(), pageResp.getMessage()); - List dataList = CollUtil.emptyIfNull(pageResp.getDataList()); - IWorkSyncProcessor.BatchResult result = syncProcessor.syncUsers(dataList, options); - updateStat(stat, result, dataList.size()); - return new BatchExecution(result, dataList.size()); - }); - } - } diff --git a/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/service/oauth2/OAuth2TokenService.java b/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/service/oauth2/OAuth2TokenService.java index d3141cfd..9cd37431 100644 --- a/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/service/oauth2/OAuth2TokenService.java +++ b/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/service/oauth2/OAuth2TokenService.java @@ -69,6 +69,16 @@ public interface OAuth2TokenService { */ OAuth2AccessTokenDO removeAccessToken(String accessToken); + /** + * 按 userId + clientId 批量移除访问令牌 + * 注意:该流程中,会移除相关的刷新令牌 + * + * @param userId 用户编号 + * @param clientId 客户端编号 + * @return 是否成功移除 + */ + boolean removeAccessTokensByUserIdAndClientId(Long userId, String clientId); + /** * 获得访问令牌分页 * diff --git a/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/service/oauth2/OAuth2TokenServiceImpl.java b/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/service/oauth2/OAuth2TokenServiceImpl.java index eee1404e..bdf08016 100644 --- a/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/service/oauth2/OAuth2TokenServiceImpl.java +++ b/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/service/oauth2/OAuth2TokenServiceImpl.java @@ -152,6 +152,18 @@ public class OAuth2TokenServiceImpl implements OAuth2TokenService { return accessTokenDO; } + @Override + @Transactional(rollbackFor = Exception.class) + public boolean removeAccessTokensByUserIdAndClientId(Long userId, String clientId) { + List accessTokenDOs = oauth2AccessTokenMapper.selectListByUserIdAndClientId(userId, clientId); + if (CollUtil.isNotEmpty(accessTokenDOs)) { + oauth2AccessTokenMapper.deleteByIds(convertSet(accessTokenDOs, OAuth2AccessTokenDO::getId)); + oauth2AccessTokenRedisDAO.deleteList(convertSet(accessTokenDOs, OAuth2AccessTokenDO::getAccessToken)); + } + int refreshRows = oauth2RefreshTokenMapper.deleteByUserIdAndClientId(userId, clientId); + return CollUtil.isNotEmpty(accessTokenDOs) || refreshRows > 0; + } + @Override public PageResult getAccessTokenPage(OAuth2AccessTokenPageReqVO reqVO) { return oauth2AccessTokenMapper.selectPage(reqVO);