diff --git a/pjcloud-integrated/pjcloud-integrated-biz/src/main/java/com/bsd/pjcloud/integrated/controller/AppMenuOpenController.java b/pjcloud-integrated/pjcloud-integrated-biz/src/main/java/com/bsd/pjcloud/integrated/controller/AppMenuOpenController.java index 68afcbb78..68592c173 100644 --- a/pjcloud-integrated/pjcloud-integrated-biz/src/main/java/com/bsd/pjcloud/integrated/controller/AppMenuOpenController.java +++ b/pjcloud-integrated/pjcloud-integrated-biz/src/main/java/com/bsd/pjcloud/integrated/controller/AppMenuOpenController.java @@ -57,11 +57,8 @@ public class AppMenuOpenController { if (!isValidAppCredentials(appId, appSecret)) { return R.failed("无效的应用ID或密钥"); } - //todo 由于浙政钉还要irs发布太麻烦,先写死吧,下次更新在由前端控制 - R> listR = remoteAppMenuService.innerAppList(typeEnum, AppMenuPlatformEnum.ZZD); -// List list = listR.getData().stream().filter(appMenu -> appMenu.getZzdVisible() != null).toList(); -// listR.setData(list); - return listR; + // 按前端 platformEnum 区分:WECHAT(10) / ZZD(30) / SHPJ(40),勿写死浙政钉 + return remoteAppMenuService.innerAppList(typeEnum, platformEnum); } private boolean isValidAppCredentials(String appId, String appSecret) { diff --git a/pjcloud-thirdparty/pjcloud-thirdparty-api/src/main/java/com/bsd/pjcloud/thirdparty/constant/UserTypeEnum.java b/pjcloud-thirdparty/pjcloud-thirdparty-api/src/main/java/com/bsd/pjcloud/thirdparty/constant/UserTypeEnum.java index 1edec6b31..5c5a0d6a1 100644 --- a/pjcloud-thirdparty/pjcloud-thirdparty-api/src/main/java/com/bsd/pjcloud/thirdparty/constant/UserTypeEnum.java +++ b/pjcloud-thirdparty/pjcloud-thirdparty-api/src/main/java/com/bsd/pjcloud/thirdparty/constant/UserTypeEnum.java @@ -4,7 +4,7 @@ import lombok.AllArgsConstructor; import lombok.Getter; /** - * 出库入口 + * 出库入口 / 单点日志 apiName */ @AllArgsConstructor @Getter @@ -12,6 +12,9 @@ public enum UserTypeEnum { ZZD("1", "浙政钉用户登录失败"), SH("2", "诗画用户登录失败"), + ZZD_OPEN_GETTOKEN("10", "浙政钉开放平台-gettoken"), + ZZD_OPEN_APP_USER("11", "浙政钉开放平台-dingtalk_app_user"), + ZZD_SSO("12", "浙政钉单点-/zzdsso"), ; private final String type; private final String description; diff --git a/pjcloud-thirdparty/pjcloud-thirdparty-biz/src/main/java/com/bsd/pjcloud/thirdparty/controller/ThirdPartyOAth2Cotroller.java b/pjcloud-thirdparty/pjcloud-thirdparty-biz/src/main/java/com/bsd/pjcloud/thirdparty/controller/ThirdPartyOAth2Cotroller.java index 723a7fba8..179fa8dc9 100644 --- a/pjcloud-thirdparty/pjcloud-thirdparty-biz/src/main/java/com/bsd/pjcloud/thirdparty/controller/ThirdPartyOAth2Cotroller.java +++ b/pjcloud-thirdparty/pjcloud-thirdparty-biz/src/main/java/com/bsd/pjcloud/thirdparty/controller/ThirdPartyOAth2Cotroller.java @@ -20,6 +20,7 @@ import com.bsd.pjcloud.thirdparty.service.SmsService; import com.bsd.pjcloud.thirdparty.exception.ThirdPartyException; import com.bsd.pjcloud.thirdparty.vo.ZzdJsapiConfigVO; import com.bsd.pjcloud.thirdparty.constant.ThirdPartyZzdBizCodes; +import com.bsd.pjcloud.thirdparty.constant.UserTypeEnum; import com.bsd.pjcloud.thirdparty.entity.ThirdPartyZzdPhoneBindEntity; import com.bsd.pjcloud.thirdparty.service.ThirdPartyOAuth2Service; import com.bsd.pjcloud.thirdparty.service.ThirdPartyUserService; @@ -104,44 +105,104 @@ public class ThirdPartyOAth2Cotroller { @GlobalTransactional @Transactional(rollbackFor = Exception.class) public R zzdsso(@RequestBody UrlTokenDTO urlTokenDTO) { + long startMs = System.currentTimeMillis(); String authCode = urlTokenDTO != null ? urlTokenDTO.getAuthCode() : null; + String reqParam = "authCode=" + StringUtils.defaultString(authCode) + + ",startMs=" + startMs; if (StringUtils.isBlank(authCode)) { + thirdPartyOAuth2Service.recordSsoLog(UserTypeEnum.ZZD_SSO.getDescription() + "-失败", + "/thirdPartyOAth2/zzdsso", reqParam, null, + "FAIL", "PARAM", "请传入浙政钉 authCode(H5 免登临时码)"); return R.failed("请传入浙政钉 authCode(H5 免登临时码)"); } - ZZDUserDTO zzdUserDTO = thirdPartyOAuth2Service.zzdssoByAuthCode(authCode.trim()); - log.warn("[zzdsso][ZZDUserDTO_JSON] 浙政钉开放平台映射后的对象,可整段复制做本地写死调试(含姓名手机号等敏感信息,调试完建议关日志或删此行) body={}", JSON.toJSONString(zzdUserDTO)); - ZZDUserDTO.Ext ext = zzdUserDTO.getExt(); - String employeeCode = ext != null ? ext.getEmployeeCode() : null; - String zzdOpenId = ext != null ? ext.getOpenid() : null; - String mobile = zzdUserDTO.getMobile(); + try { + ZZDUserDTO zzdUserDTO = thirdPartyOAuth2Service.zzdssoByAuthCode(authCode.trim()); + log.warn("[zzdsso][ZZDUserDTO_JSON] 浙政钉开放平台映射后的对象,可整段复制做本地写死调试(含姓名手机号等敏感信息,调试完建议关日志或删此行) body={}", JSON.toJSONString(zzdUserDTO)); + ZZDUserDTO.Ext ext = zzdUserDTO.getExt(); + String employeeCode = ext != null ? ext.getEmployeeCode() : null; + String zzdOpenId = ext != null ? ext.getOpenid() : null; + String mobile = zzdUserDTO.getMobile(); + reqParam = reqParam + ",employeeCode=" + StringUtils.defaultString(employeeCode) + + ",openid=" + StringUtils.defaultString(zzdOpenId) + + ",mobile=" + StringUtils.defaultString(mobile) + + ",nickName=" + StringUtils.defaultString(zzdUserDTO.getNickName()); - if (thirdPartyZzdSmsBindService.isEnabled()) { - var boundOpt = thirdPartyZzdSmsBindService.findBound(employeeCode, zzdOpenId); - if (boundOpt.isPresent()) { - ThirdPartyZzdPhoneBindEntity bound = boundOpt.get(); - return buildZzdSsoTokenResult(bound.getEmployeeCode(), bound.getVerifiedPhone()); - } - try { - ZzdUserSnapshot snap = ThirdPartyZzdSmsBindService.snapshotOf(zzdUserDTO); - if (StringUtils.isBlank(snap.getEmployeeCode()) && StringUtils.isBlank(snap.getOpenid())) { - return R.failed("浙政钉未返回员工编码或 openid,无法绑定登录"); + if (thirdPartyZzdSmsBindService.isEnabled()) { + var boundOpt = thirdPartyZzdSmsBindService.findBound(employeeCode, zzdOpenId); + if (boundOpt.isPresent()) { + ThirdPartyZzdPhoneBindEntity bound = boundOpt.get(); + R result = buildZzdSsoTokenResult(bound.getEmployeeCode(), bound.getVerifiedPhone()); + recordZzdSsoControllerLog("/thirdPartyOAth2/zzdsso", reqParam, result, startMs, "boundUser"); + return result; } - if (StringUtils.isBlank(snap.getEmployeeCode())) { - return R.failed("浙政钉未返回员工编码,无法完成首次手机号绑定,请在开放平台核对应用权限或联系管理员。"); + try { + ZzdUserSnapshot snap = ThirdPartyZzdSmsBindService.snapshotOf(zzdUserDTO); + if (StringUtils.isBlank(snap.getEmployeeCode()) && StringUtils.isBlank(snap.getOpenid())) { + R failed = R.failed("浙政钉未返回员工编码或 openid,无法绑定登录"); + recordZzdSsoControllerLog("/thirdPartyOAth2/zzdsso", reqParam, failed, startMs, "needBind"); + return failed; + } + if (StringUtils.isBlank(snap.getEmployeeCode())) { + R failed = R.failed("浙政钉未返回员工编码,无法完成首次手机号绑定,请在开放平台核对应用权限或联系管理员。"); + recordZzdSsoControllerLog("/thirdPartyOAth2/zzdsso", reqParam, failed, startMs, "needBind"); + return failed; + } + String bindSessionId = thirdPartyZzdSmsBindService.createBindSession(snap); + HashMap need = new HashMap<>(); + need.put("needSmsVerify", Boolean.TRUE); + need.put("bindSessionId", bindSessionId); + need.put("displayName", StringUtils.defaultIfBlank(zzdUserDTO.getNickName(), zzdUserDTO.getUsername())); + R ok = R.ok(need); + recordZzdSsoControllerLog("/thirdPartyOAth2/zzdsso", reqParam, ok, startMs, "needSmsVerify"); + return ok; + } catch (JsonProcessingException e) { + R failed = R.failed("创建绑定会话失败"); + recordZzdSsoControllerLog("/thirdPartyOAth2/zzdsso", reqParam, failed, startMs, "needBind"); + return failed; } - String bindSessionId = thirdPartyZzdSmsBindService.createBindSession(snap); - HashMap need = new HashMap<>(); - need.put("needSmsVerify", Boolean.TRUE); - need.put("bindSessionId", bindSessionId); - need.put("displayName", StringUtils.defaultIfBlank(zzdUserDTO.getNickName(), zzdUserDTO.getUsername())); - return R.ok(need); - } catch (JsonProcessingException e) { - return R.failed("创建绑定会话失败"); } + + R result = buildZzdSsoTokenResult(employeeCode, mobile); + recordZzdSsoControllerLog("/thirdPartyOAth2/zzdsso", reqParam, result, startMs, "directToken"); + return result; + } catch (ThirdPartyException e) { + thirdPartyOAuth2Service.recordSsoLog(UserTypeEnum.ZZD_SSO.getDescription() + "-失败", + "/thirdPartyOAth2/zzdsso", reqParam, + "costMs=" + (System.currentTimeMillis() - startMs), + "FAIL", e.getCode(), e.getMessage()); + return R.failed(e.getMessage()); + } catch (Exception e) { + log.error("[zzdsso] 未预期异常", e); + thirdPartyOAuth2Service.recordSsoLog(UserTypeEnum.ZZD_SSO.getDescription() + "-失败", + "/thirdPartyOAth2/zzdsso", reqParam, + "costMs=" + (System.currentTimeMillis() - startMs), + "FAIL", "ZZD_SSO_UNEXPECTED", e.getMessage()); + return R.failed("浙政钉单点登录失败"); } + } - return buildZzdSsoTokenResult(employeeCode, mobile); + /** + * 记录 /zzdsso 业务结果(成功发 token / 需短信 / 业务失败),与开放平台 SDK 调用日志分开查。 + */ + private void recordZzdSsoControllerLog(String requestUrl, String reqParam, R result, long startMs, String stage) { + boolean ok = result != null && result.getCode() == 0; + HashMap body = new HashMap<>(); + body.put("stage", stage); + body.put("costMs", System.currentTimeMillis() - startMs); + body.put("code", result != null ? result.getCode() : null); + body.put("msg", result != null ? result.getMsg() : null); + if (result != null && result.getData() != null) { + body.put("data", result.getData()); + } + thirdPartyOAuth2Service.recordSsoLog( + UserTypeEnum.ZZD_SSO.getDescription() + (ok ? "-成功" : "-失败"), + requestUrl, + reqParam, + JSON.toJSONString(body), + ok ? "OK" : "FAIL", + ok ? "0" : String.valueOf(result != null ? result.getCode() : -1), + ok ? null : (result != null ? result.getMsg() : "unknown")); } /** @@ -153,35 +214,53 @@ public class ThirdPartyOAth2Cotroller { @Inner(value = false) @Transactional(rollbackFor = Exception.class) public R confirmZzdPhoneBind(@RequestBody ZzdPhoneConfirmDTO dto) { + long startMs = System.currentTimeMillis(); + String reqParam = "bindSessionId=" + (dto != null ? StringUtils.defaultString(dto.getBindSessionId()) : "") + + ",mobilePhone=" + (dto != null ? StringUtils.defaultString(dto.getMobilePhone()) : "") + + ",smsCode=" + (dto != null ? StringUtils.defaultString(dto.getSmsCode()) : "") + + ",startMs=" + startMs; if (dto == null || StringUtils.isAnyBlank(dto.getBindSessionId(), dto.getMobilePhone(), dto.getSmsCode())) { - return R.failed("参数不完整"); + R failed = R.failed("参数不完整"); + recordZzdSsoControllerLog("/thirdPartyOAth2/zzdsso/confirmPhone", reqParam, failed, startMs, "confirmPhone"); + return failed; } try { ZzdUserSnapshot snap = thirdPartyZzdSmsBindService.getBindSession(dto.getBindSessionId()); if (snap == null) { - return R.failed("绑定会话已过期,请重新登录"); + R failed = R.failed("绑定会话已过期,请重新登录"); + recordZzdSsoControllerLog("/thirdPartyOAth2/zzdsso/confirmPhone", reqParam, failed, startMs, "confirmPhone"); + return failed; } if (StringUtils.isBlank(snap.getEmployeeCode())) { - return R.failed("会话数据异常"); + R failed = R.failed("会话数据异常"); + recordZzdSsoControllerLog("/thirdPartyOAth2/zzdsso/confirmPhone", reqParam, failed, startMs, "confirmPhone"); + return failed; } + reqParam = reqParam + ",employeeCode=" + snap.getEmployeeCode(); String redisKey = CacheConstants.SMS_CODE_KEY + dto.getMobilePhone(); String storedCode = (String) redisTemplate.opsForValue().get(redisKey); if (!dto.getSmsCode().equals(storedCode)) { - return R.failed("验证码错误"); + R failed = R.failed("验证码错误"); + recordZzdSsoControllerLog("/thirdPartyOAth2/zzdsso/confirmPhone", reqParam, failed, startMs, "confirmPhone"); + return failed; } redisTemplate.delete(redisKey); R> byPhone = remoteUserService.getUserByMobile(dto.getMobilePhone()); List users = byPhone.getData(); if (CollectionUtils.isEmpty(users)) { - return R.failed(ThirdPartyZzdBizCodes.SYS_USER_NOT_FOUND_FOR_ZZD_BIND, + R failed = R.failed(ThirdPartyZzdBizCodes.SYS_USER_NOT_FOUND_FOR_ZZD_BIND, "本系统暂无该手机号对应的用户,请联系管理员申请开通账号后再完成绑定。"); + recordZzdSsoControllerLog("/thirdPartyOAth2/zzdsso/confirmPhone", reqParam, failed, startMs, "confirmPhone"); + return failed; } SysUser sysUser = users.get(0); if (StringUtils.isNotBlank(sysUser.getDingtalkEmployeeCode()) && StringUtils.isNotBlank(snap.getEmployeeCode()) && !sysUser.getDingtalkEmployeeCode().equals(snap.getEmployeeCode())) { - return R.failed("浙政钉账号与本系统用户不一致"); + R failed = R.failed("浙政钉账号与本系统用户不一致"); + recordZzdSsoControllerLog("/thirdPartyOAth2/zzdsso/confirmPhone", reqParam, failed, startMs, "confirmPhone"); + return failed; } thirdPartyZzdSmsBindService.recordVerifiedBind(snap, dto.getMobilePhone()); @@ -193,9 +272,20 @@ public class ThirdPartyOAth2Cotroller { HashMap out = new HashMap<>(); out.put("refreshToken", r.getData().get("refreshToken")); out.put("accessToken", r.getData().get("accessToken")); - return R.ok(out); + R ok = R.ok(out); + recordZzdSsoControllerLog("/thirdPartyOAth2/zzdsso/confirmPhone", reqParam, ok, startMs, "confirmPhone"); + return ok; } catch (JsonProcessingException e) { - return R.failed("保存绑定信息失败"); + R failed = R.failed("保存绑定信息失败"); + recordZzdSsoControllerLog("/thirdPartyOAth2/zzdsso/confirmPhone", reqParam, failed, startMs, "confirmPhone"); + return failed; + } catch (Exception e) { + log.error("[zzdsso/confirmPhone] 未预期异常", e); + thirdPartyOAuth2Service.recordSsoLog(UserTypeEnum.ZZD_SSO.getDescription() + "-失败", + "/thirdPartyOAth2/zzdsso/confirmPhone", reqParam, + "costMs=" + (System.currentTimeMillis() - startMs), + "FAIL", "ZZD_CONFIRM_UNEXPECTED", e.getMessage()); + return R.failed("短信核验失败"); } } diff --git a/pjcloud-thirdparty/pjcloud-thirdparty-biz/src/main/java/com/bsd/pjcloud/thirdparty/service/ThirdPartyOAuth2Service.java b/pjcloud-thirdparty/pjcloud-thirdparty-biz/src/main/java/com/bsd/pjcloud/thirdparty/service/ThirdPartyOAuth2Service.java index e82b45bf5..a5419267b 100644 --- a/pjcloud-thirdparty/pjcloud-thirdparty-biz/src/main/java/com/bsd/pjcloud/thirdparty/service/ThirdPartyOAuth2Service.java +++ b/pjcloud-thirdparty/pjcloud-thirdparty-biz/src/main/java/com/bsd/pjcloud/thirdparty/service/ThirdPartyOAuth2Service.java @@ -395,9 +395,47 @@ public class ThirdPartyOAuth2Service { if (zzdOpenPlatform.isEnabled() && zzdOpenPlatform.isAppCredentialConfigured()) { return getZzdUserByOpenPlatformAuthCode(authCode); } + recordSsoLog(UserTypeEnum.ZZD_SSO.getDescription() + "-失败", + "/thirdPartyOAth2/zzdsso", + "authCode=" + (authCode != null ? authCode : ""), + null, + "CONFIG", + "ZZD_OPEN_CONFIG", + "浙政钉单点需配置 zzd.open.enabled 与 app-key/app-secret"); throw new ThirdPartyException("浙政钉单点需配置 zzd.open.enabled 与 app-key/app-secret(开放平台企业内应用)", "ZZD_OPEN_CONFIG"); } + /** + * 写入单点日志表 third_party_log(异步),成功/失败都记;后台分析用,不做脱敏。 + */ + public void recordSsoLog(String apiName, String requestUrl, String requestParameter, + String responseBody, String httpStatus, String errorCode, String errorMsg) { + try { + ThirdPartyLogEntity entity = new ThirdPartyLogEntity(); + entity.setApiName(apiName); + entity.setRequestUrl(requestUrl); + entity.setRequestParameter(truncate(requestParameter, 8000)); + entity.setResponseBody(truncate(responseBody, 16000)); + entity.setHttpStatus(httpStatus); + entity.setErrorCode(errorCode); + entity.setErrorMsg(truncate(errorMsg, 2000)); + entity.setCreateBy("zzd-openapi"); + thirdPartyLogService.saveLog(entity); + } catch (Exception e) { + log.warn("写入单点日志失败 apiName={}", apiName, e); + } + } + + private static String truncate(String s, int max) { + if (s == null) { + return null; + } + if (s.length() <= max) { + return s; + } + return s.substring(0, max) + "...(truncated)"; + } + /** * 开放平台:官方 SDK {@code IntelligentGetClient /gettoken.json},解析 content.data 中 accessToken */ @@ -411,6 +449,11 @@ public class ThirdPartyOAuth2Service { if (zzdOpenCachedAppAccessToken != null && now < zzdOpenCachedAppAccessTokenExpireMs - 60_000L) { return zzdOpenCachedAppAccessToken; } + String reqLog = "appkey=" + zzdOpenPlatform.getAppKey() + + ",appsecret=" + zzdOpenPlatform.getAppSecret() + + ",domain=" + zzdOpenPlatform.getDomain() + + ",time=" + System.currentTimeMillis(); + String lastRespBody = null; try { ExecutableClient ec = zzdExecutableClientHolder.client(); IntelligentGetClient getClient = ec.newIntelligentGetClient("/gettoken.json"); @@ -420,6 +463,7 @@ public class ThirdPartyOAuth2Service { OapiGettokenJsonResponse resp = getClient.get(req); zzdAssertSdkTopSuccess(resp, "gettoken"); JSONObject data = zzdSdkSpResultData(resp.getContent(), "gettoken"); + lastRespBody = data != null ? data.toJSONString() : null; String accessToken = data.getString("accessToken"); if (!StringUtils.hasText(accessToken)) { throw new ThirdPartyException("浙政钉 gettoken 未返回 accessToken", "ZZD_OPEN_TOKEN_BAD"); @@ -434,11 +478,24 @@ public class ThirdPartyOAuth2Service { } zzdOpenCachedAppAccessToken = accessToken; zzdOpenCachedAppAccessTokenExpireMs = System.currentTimeMillis() + expiresIn * 1000L; + JSONObject okBody = new JSONObject(); + okBody.put("accessToken", accessToken); + okBody.put("expiresIn", expiresIn); + okBody.put("cachedExpireAt", zzdOpenCachedAppAccessTokenExpireMs); + recordSsoLog(UserTypeEnum.ZZD_OPEN_GETTOKEN.getDescription() + "-成功", + "/gettoken.json", reqLog, okBody.toJSONString(), + "OK", "0", null); return accessToken; } catch (ThirdPartyException e) { + recordSsoLog(UserTypeEnum.ZZD_OPEN_GETTOKEN.getDescription() + "-失败", + "/gettoken.json", reqLog, lastRespBody, + "FAIL", e.getCode(), e.getMessage()); throw e; } catch (Exception e) { log.error("浙政钉 gettoken SDK 调用异常", e); + recordSsoLog(UserTypeEnum.ZZD_OPEN_GETTOKEN.getDescription() + "-失败", + "/gettoken.json", reqLog, lastRespBody, + "FAIL", "ZZD_OPEN_TOKEN_SDK", e.getMessage()); throw new ThirdPartyException("浙政钉获取应用 access_token 失败", "ZZD_OPEN_TOKEN_SDK"); } } @@ -448,8 +505,10 @@ public class ThirdPartyOAuth2Service { * 官方 SDK {@code IntelligentPostClient /rpc/oauth2/dingtalk_app_user.json} */ private ZZDUserDTO getZzdUserByOpenPlatformAuthCode(String authCode) { + String reqLog = "auth_code=" + authCode + ",time=" + System.currentTimeMillis(); try { String appToken = getZzdOpenAppAccessToken(); + reqLog = reqLog + ",access_token=" + appToken; ExecutableClient ec = zzdExecutableClientHolder.client(); IntelligentPostClient postClient = ec.newIntelligentPostClient("/rpc/oauth2/dingtalk_app_user.json"); OapiRpcOauth2DingtalkAppUserJsonRequest req = new OapiRpcOauth2DingtalkAppUserJsonRequest(); @@ -469,11 +528,23 @@ public class ThirdPartyOAuth2Service { && !zzdOpenPlatform.getTenantId().equals(dto.getExt().getRealmId())) { log.warn("浙政钉用户 realmId={} 与配置 zzd.open.tenant-id={} 不一致", dto.getExt().getRealmId(), zzdOpenPlatform.getTenantId()); } + JSONObject successBody = new JSONObject(); + successBody.put("rawContent", rawContent); + successBody.put("mappedUser", JSON.toJSON(dto)); + recordSsoLog(UserTypeEnum.ZZD_OPEN_APP_USER.getDescription() + "-成功", + "/rpc/oauth2/dingtalk_app_user.json", reqLog, successBody.toJSONString(), + "OK", "0", null); return dto; } catch (ThirdPartyException e) { + recordSsoLog(UserTypeEnum.ZZD_OPEN_APP_USER.getDescription() + "-失败", + "/rpc/oauth2/dingtalk_app_user.json", reqLog, null, + "FAIL", e.getCode(), e.getMessage()); throw e; } catch (Exception e) { log.error("浙政钉 dingtalk_app_user SDK 调用异常", e); + recordSsoLog(UserTypeEnum.ZZD_OPEN_APP_USER.getDescription() + "-失败", + "/rpc/oauth2/dingtalk_app_user.json", reqLog, null, + "FAIL", "ZZD_OPEN_USER_SDK", e.getMessage()); throw new ThirdPartyException("浙政钉获取用户失败", "ZZD_OPEN_USER_SDK"); } }