若依
本章节演示Ruoyi-vue框架对接MDP
本章节采用Ruoyi-vue的3.9.2版本对接MDP的1.3.0版本,对接完成之后的代码已经上传到了对应的仓库 (切换到 tag mdp-ruoyi-1.3.0)
- MDP 后端: https://gitee.com/henhen6/mddata
- MDP 前端: https://gitee.com/henhen6/mdp-web-vben
- Ruoyi-vue: https://gitee.com/henhen6/RuoYi-Vue
在MDP平台配置应用
配置应用
注意
配置应用可以联系MDP系统的管理员,由管理员在【控制台】配置,也可以自行登录MDP的【开发者中心】自行申请应用。

联系管理员,登录MDP【控制台】-【开放平台】-【应用管理】页面,点击[新增]按钮新建应用。登录方式选择【单点登录】。
应用新建后,应用ID和应用秘钥会自动生成,可点击【秘钥】按钮查看
字段说明
字段 值 说明 应用名称 若依sso 应用图标 应用ID ruoyi-vue-sso 系统自动生成 应用类型 第三方应用 仅用于区分应用是否自建 状态 true 禁用后,无法单点登录到此应用 权重 在我的应用列表的排序 应用简介 展示在我的应用列表 备注 仅用于后台查看 是否公开 false true:任何人可以查看和登录;false:有权限的用户才能查看和登录该应用 是否显示 true true:在我的应用列表显示;false:在我的应用列表隐藏 首页地址 允许授权的IP 多个ip使用英文逗号分割;数据接口调用和回调时,会校验IP地址是否与之匹配。 登录方式 单点登录 单点登录:sa-token的模式3 Oauth2:标准的Oauth2协议 自动登录地址 http://localhost:1024/login 在我的应用页面,点击跳转到子平台时完成自动登录 允许授权地址 http://localhost:1024/login 此配置允许使用 * 通配符,多个地址使用 , 分割 是否接收推送 true 使用模式三对接的应用必须依托“接收消息推送”才可以完成单点注销服务 单点注销推送 true 接收包括单点注销在内的所有消息推送 消息推送地址 http://localhost:18080/sso/pushC 应用后台接口,用于接收消息推送和单点注销推送。 配置秘钥
点击【秘钥】按钮,可以查看应用ID和应用秘钥,并配置事件订阅和公私钥。
事件订阅
事件订阅:MDP系统提前内置了一些“主数据”,在MDP平台操作了这些主数据后,会通过事件的方式广播给所有订阅了这个事件的应用,应用在接收到对应的事件后,需要自行编写代码接收和存储数据。
平台在推送事件时,会将全部参数使用【平台私钥】进行签名。应用在接收到消息后,需要使用【平台公钥】对签名进行验签,验签成功后方可处理事件逻辑。
应用在调用平台提供的接口时,需要将全部参数使用【应用私钥】进行签名。应用在接收到调用请求后,需要使用【应用公钥】对签名进行验签,验签成功后才会响应应用数据。
字段 值 说明 事件订阅状态 启用 启用:主数据变更时通知该应用。禁用:不通知 通知地址 http://127.0.0.1:18080/callback/notify 应用接收事件订阅的接口地址 加密类型 sm4加密 平台在推送消息时,签名的加密算法 订阅的事件 平台内置的事件 应用公私钥
公私钥:MDP提供了一些开放接口供应用调用,应用在调用时,需要使用【平台公钥】和【应用私钥】。 为了安全起见,应用公钥和私钥应该由应用方自行生成,并将私钥妥善保存,公钥配置在MDP系统中。
应用公钥:应用自行生成,需提供给平台。
应用私钥:应用自行生成,应用自行存储,不要泄露给第三方。
平台公钥:平台自行生成,需提供给应用。
平台私钥:平台自行生成,平台自行存储,不要泄露给第三方。
ps: MDP平台为了简化应用的使用难度,提供了【重置应用公私钥】按钮。所以会存储应用私钥,二次开发过程中,可以按需删除这个功能。

Ruoyi-vue项目对接单点登录
用户表新增字段
sys_user表新增sso_id字段
-- 给sys_user表新增sso_id字段 ALTER TABLE sys_user ADD COLUMN sso_id BIGINT NULL COMMENT '单点登录中心的用户id';SysUser实体新增ssoId字段
public class SysUser extends BaseEntity { /** 单点登录中心的用户id */ private Long ssoId; }
新增根据ssoId查询用户的方法
serivce
public interface ISysUserService { SysUser getUserBySsoId(Long ssoId); } @Service public class SysUserServiceImpl implements ISysUserService { @Override public SysUser getUserBySsoId(Long ssoUserId) { return userMapper.getUserBySsoId(ssoUserId); } }mapper
public interface SysUserMapper { SysUser getUserBySsoId(Long ssoId); } // SysUserMapper.xml <select id="getUserBySsoId" parameterType="Long" resultMap="SysUserResult"> select * from sys_user where sso_id = #{ssoId} </select>
开发新接口
ruoyi-admin/pom.xml 添加依赖
<!-- Sa-Token 插件:整合SSO --> <dependency> <groupId>cn.dev33</groupId> <artifactId>sa-token-sso</artifactId> <version>1.45.0</version> </dependency> <!-- Sa-Token 插件:整合 Forest 请求工具 --> <dependency> <groupId>cn.dev33</groupId> <artifactId>sa-token-forest</artifactId> <version>1.45.0</version> </dependency> <dependency> <groupId>cn.dev33</groupId> <artifactId>sa-token-spring-boot4-starter</artifactId> <version>1.45.0</version> </dependency>开发Controller接口(getSsoAuthUrl、doLoginByTicket)
package com.ruoyi.web.controller; import cn.dev33.satoken.sso.model.SaCheckTicketResult; import cn.dev33.satoken.sso.processor.SaSsoClientProcessor; import cn.dev33.satoken.sso.template.SaSsoClientUtil; import cn.dev33.satoken.stp.StpUtil; import cn.dev33.satoken.util.SaResult; import com.ruoyi.common.core.domain.AjaxResult; import com.ruoyi.common.core.text.Convert; import com.ruoyi.framework.web.service.SysLoginService; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; /** * 单点登录 客户端接口 */ @RestController @RequestMapping() @Tag(name = "单点登录客户端") public class SsoClientController { @Autowired private SysLoginService sysLoginService; /** * 返回 MDP单点登录中心 的SSO登录地址 (前后台分离环境下专用) * * ruoyi-ui 检测到用户没有登录时(没有缓存token也没有检测到ticket),需要调用该接口,然后重定向到该接口返回的地址 */ @Operation(summary = "获取SSO认证中心登录地址", description = "获取SSO认证中心登录地址") @GetMapping("/anyUser/sso/getSsoAuthUrl") public AjaxResult getSsoAuthUrl(String clientLoginUrl) { String serverAuthUrl = SaSsoClientUtil.buildServerAuthUrl(clientLoginUrl, ""); return AjaxResult.success("操作成功", serverAuthUrl); } /** * 根据ticket获取token * * 在MDP单点登录中心(getSsoAuthUrl方法返回的地址)登录成功后,MDP会写单 ticket 重定向到ruoyi-ui的登录页,ruoyi-ui的登录页获取 ticket后,调用此方法,去MDP单点登录中心验证ticket是否有效,校验成功视为登录成功,校验失败不允许登录。 * * 该接口会根据is-http判断是否调用 MDP单点登录中心 的pushS接口 * * @param ticket ticket * @return token */ @Operation(summary = "根据ticket获取token", description = "校验ticket有限性,并返回token") @GetMapping("/anyUser/sso/doLoginByTicket") public AjaxResult doLoginByTicket(String ticket) { // 校验ticket (若校验失败,这个方法会直接报错) SaCheckTicketResult ctr = SaSsoClientProcessor.instance.checkTicket(ticket); // 校验成功:则根据sso的用户id,查询 若依的用户, 然后生成若依系统的token。 String token = sysLoginService.login(Convert.toLong(ctr.loginId)); return AjaxResult.success("操作成功", token); } }开发SysLoginService
@Component public class SysLoginService { @Autowired private ISysUserService userService; // 该接口的登录逻辑与Ruoyi-vue原始提供的 String login(String username, String password, String code, String uuid) 接口逻辑基本一致。 少许不同之处请查看源码。 public String login(Long ssoId) { SysUser user = userService.getUserBySsoId(ssoId); if (StringUtils.isNull(user)) { log.info("登录用户:{} 不存在.", ssoId); throw new ServiceException(MessageUtils.message("user.not.exists")); } else if (UserStatus.DELETED.getCode().equals(user.getDelFlag())) { log.info("登录用户:{} 已被删除.", ssoId); throw new ServiceException(MessageUtils.message("user.password.delete")); } else if (UserStatus.DISABLE.getCode().equals(user.getStatus())) { log.info("登录用户:{} 已被停用.", ssoId); throw new ServiceException(MessageUtils.message("user.blocked")); } // 用户验证 Authentication authentication = null; try { UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(user.getUserName(), user.getPassword()); AuthenticationContextHolder.setContext(authenticationToken); // 该方法会去调用UserDetailsServiceImpl.loadUserByUsername authentication = authenticationManager.authenticate(authenticationToken); } catch (Exception e) { if (e instanceof BadCredentialsException) { AsyncManager.me().execute(AsyncFactory.recordLogininfor(user.getUserName(), Constants.LOGIN_FAIL, MessageUtils.message("user.password.not.match"))); throw new UserPasswordNotMatchException(); } else { AsyncManager.me().execute(AsyncFactory.recordLogininfor(user.getUserName(), Constants.LOGIN_FAIL, e.getMessage())); throw new ServiceException(e.getMessage()); } } finally { AuthenticationContextHolder.clearContext(); } AsyncManager.me().execute(AsyncFactory.recordLogininfor(user.getUserName(), Constants.LOGIN_SUCCESS, MessageUtils.message("user.login.success"))); LoginUser loginUser = (LoginUser) authentication.getPrincipal(); recordLoginInfo(loginUser.getUserId()); // 生成token return tokenService.createToken(loginUser); } }1
调整 SecurityConfig 类配置
@EnableMethodSecurity(prePostEnabled = true, securedEnabled = true) @Configuration public class SecurityConfig { /** * 自定义用户认证逻辑 */ @Autowired private UserDetailsService userDetailsService; @Bean public AuthenticationManager authenticationManager() { DaoAuthenticationProvider daoAuthenticationProvider = new DaoAuthenticationProvider(userDetailsService); // 重新制定密码验证器 daoAuthenticationProvider.setPasswordEncoder(bCryptPasswordEncoder()); return new ProviderManager(daoAuthenticationProvider); } /** * 自定义加密实现 */ @Bean public BCryptPasswordEncoder bCryptPasswordEncoder() { return new MyBCryptPasswordEncoder(); } @Bean protected SecurityFilterChain filterChain(HttpSecurity httpSecurity) throws Exception { return httpSecurity .authorizeHttpRequests((requests) -> { permitAllUrl.getUrls().forEach(url -> requests.requestMatchers(url).permitAll()); requests.requestMatchers("/login", "/register", "/captchaImage").permitAll() // TODO 关键点:单点登录相关接口忽略权限 (匹配的是 SsoClientController 类的2个接口) .requestMatchers("/anyUser/**").permitAll() // 其他无关的配置已经省略... .anyRequest().authenticated(); }) // 其他无关的配置已经省略... .build(); } } public class MyBCryptPasswordEncoder extends BCryptPasswordEncoder { // 覆盖 父类的这个方法, 不要在校验用户的密码(密码统一交给MDP管理) @Override protected boolean matchesNonNull(String rawPassword, String encodedPassword) { return true; } }修改application.yml文件
# sa-token配置 sa-token: is-log: true sso-client: ### 以下信息 根据【应用管理】新建应用后系统生成的值自行调整 ### # 应用ID client: ruoyi-vue-sso # 应用秘钥 secret-key: 0Tvtm2xrTWG7n2azkM4FPyHwS6c3NxjQjYKh ### 以下信息 根据你的部署环境酌情修改 ip和port ### # 单体版:boot-server 访问地址 server-url: http://localhost:23455 # 微服务版:inner-gateway-server访问地址 + workbench-server的前缀 # server-url: http://localhost:23450/api/workbench # mdp-vben 前端登录地址 authUrl: 'http://localhost:7700/#/auth/login' ### 以下信息请勿修改 ### # Server 端:单点注销地址 signoutUrl: '/anyUser/sso/signout' # Server 端:推送消息地址 pushUrl: '/anyUser/sso/pushS' # Server 端:查询数据 getData 地址 getDataUrl: '/anyUser/sso/getData' # 是否使用模式3 is-http: true看图理解每一个配置
应用ID和秘钥
authUrl
单体版server-url
微服务版server-url
其他固定参数
前端
新增 login_sso.vue 页面
<template> <div class="login"> <Result v-loading="loading" :element-loading-text="msg" :title="resultMsg" class="h-full w-full"> <template #icon> <Button v-if="ticketError" @click="gotoLogin" type="primary"> 重新登录 </Button> </template> </Result> <!-- 底部 --> <div class="el-login-footer"> <span>Copyright © 2018-2025 ruoyi.vip All Rights Reserved.</span> </div> </div> </template> <script> import { Button, Result } from 'element-ui'; import { getParam } from '@/utils/request'; import { doLoginByTicket, getSsoAuthUrl } from '@/api/login'; export default { name: "Login_sso", components: { Button, Result, }, data() { return { loading: false, msg: '正在加载...', resultMsg: '', ticketError: false, back: '', ticket: '', } }, watch: { $route: { handler: function(route) { debugger; this.back = getParam('back') || route.query.back; this.ticket = getParam('ticket') || route.query.ticket; }, immediate: true } }, created() { debugger; // 有ticket 说明是从MDP登录之后重定向回来的,需要携带ticket到后端去验证ticket有效性 // 无ticket 说明是登录过期了,需要去MDP登录 (this.ticket ? this.handleLoginByTicket(this.ticket) : this.goSsoAuthUrl()); }, methods: { gotoLogin() { location.href = '/login'; }, handleLoginByTicket(ticket) { debugger; this.loading = true; this.msg = '单点登录成功,正在验证登录信息...'; this.resultMsg = ''; const vm = this; console.log(this); doLoginByTicket(ticket).then((res)=>{ if (res.code == 200) { this.$store.dispatch("Login2", res.data).then(() => { location.href = decodeURIComponent(vm.back); vm.loading = false; }) } }).catch((error)=>{ if ( [30004, 30005].includes(error?.data?.code) ) { this.ticketError = true; setTimeout(() => { this.loading = false; this.resultMsg = 'ticket 无效,请重新登录'; }, 500); } }) }, // 重定向至认证中心 goSsoAuthUrl() { console.log('goSsoAuthUrl'); debugger; this.loading = true; this.resultMsg = ''; this.msg = '回话失效,正在为您跳转至统一身份认证平台重新登录...'; getSsoAuthUrl(location.href).then((res) => { if (res.code === 200) { location.href = res.data; } }).catch(()=>{ setTimeout(() => { this.loading = false; this.resultMsg = '获取单点登录平台地址失败,请检查后端服务器是否正常'; }, 500); }); }, } } </script>修改其他代码
// src/api/login.js // 返回SSO认证中心登录地址 export function getSsoAuthUrl(clientLoginUrl) { return request({ url: `/anyUser/sso/getSsoAuthUrl?clientLoginUrl=${clientLoginUrl}`, method: 'get' }) } // 根据ticket进行登录 export function doLoginByTicket(ticket) { return request({ url: `/anyUser/sso/doLoginByTicket?ticket=${ticket}`, method: 'get' }) } // src/router/index.js { path: '/login', component: () => import('@/views/login_sso'), hidden: true }, // src/modules/user.js actions: { Login2({ commit }, token) { setToken(token) commit('SET_TOKEN', token) }, } // src/utils/request.js export const getParam = function (name, defaultValue) { const query = window.location.search.slice(1); const vars = query.split('&'); for (const var_ of vars) { const pair = var_.split('='); if (pair[0] === name) { return pair[1]; } } return defaultValue === undefined ? null : defaultValue; }; // src/permission.js if (isWhiteList(to.path)) { next() } else { const back = encodeURIComponent(to.fullPath); next(`/login?back=` + back) // 修改这里 NProgress.done() }
按以上步骤修改Ruoyi-vue项目的代码后,即实现了完整的单点登录对接。
Ruoyi-vue对接单点注销
Sa-token支持4种注销方式,本项目采用的是全端注销。
- 全端注销:用户在所有已登录应用中统一下线;
- 单端注销:用户只在当前客户端单独注销;
- 单应用注销:仅退出当前应用,其它应用保持登录态;
- 单浏览器注销:当前浏览器下全部应用统一下线;
修改 LogoutSuccessHandlerImpl
@Configuration public class LogoutSuccessHandlerImpl implements LogoutSuccessHandler { private static final Logger log = LoggerFactory.getLogger(LogoutSuccessHandlerImpl.class); @Autowired private TokenService tokenService; /** * 退出处理 * * @return */ @Override public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException { LoginUser loginUser = tokenService.getLoginUser(request); try { if (StringUtils.isNotNull(loginUser)) { String userName = loginUser.getUsername(); // 若依框架没有使用sa-token,所以需要自行编写代码通知平台退出 if (loginUser.getUser() != null && loginUser.getUser().getSsoId() != null) { Long ssoId = loginUser.getUser().getSsoId(); SaResult result = (SaResult) _ssoLogoutByMode3(ssoId); if (result.getCode() == SaResult.CODE_SUCCESS) { ServletUtils.renderString(response, JSON.toJSONString(AjaxResult.success(MessageUtils.message("user.logout.success")))); // 删除用户缓存记录 tokenService.delLoginUser(loginUser.getToken()); // 记录用户退出日志 AsyncManager.me().execute(AsyncFactory.recordLogininfor(userName, Constants.LOGOUT, MessageUtils.message("user.logout.success"))); } else { ServletUtils.renderString(response, JSON.toJSONString(AjaxResult.error(result.getCode(), result.getMsg()))); } } } } catch (Exception e) { log.error("退出失败", e); ServletUtils.renderString(response, JSON.toJSONString(AjaxResult.error(e.getMessage()))); } } public Object _ssoLogoutByMode3(Long loginId) { // 获取对象 SaRequest req = SaHolder.getRequest(); SaResponse res = SaHolder.getResponse(); StpLogic stpLogic = SaSsoClientProcessor.instance.ssoClientTemplate.getStpLogicOrGlobal(); boolean singleDeviceIdLogout = req.isParam(SaSsoClientProcessor.instance.ssoClientTemplate.paramName.singleDeviceIdLogout, "true"); // 如果未登录,则无需注销 if (loginId == null) { return SaSsoClientProcessor.instance._ssoLogoutBack(req, res); } // 向 sso-server 认证中心推送消息:单点注销 SaLogoutParameter logoutParameter = stpLogic.createSaLogoutParameter(); if (singleDeviceIdLogout) { logoutParameter.setDeviceId(stpLogic.getLoginDeviceId()); } Object centerId = SaSsoClientProcessor.instance.ssoClientTemplate.strategy.convertLoginIdToCenterId.run(loginId); SaSsoMessage message = SaSsoClientProcessor.instance.ssoClientTemplate.buildSignoutMessage(centerId, logoutParameter); SaResult result = SaSsoClientProcessor.instance.ssoClientTemplate.pushMessageAsSaResult(message); // 如果 sso-server 响应的状态码非200,代表业务失败,将回应的 msg 字段作为异常抛出 if (result.getCode() == null || SaResult.CODE_SUCCESS != result.getCode()) { throw new SaSsoException(result.getMsg()).setCode(SaSsoErrorCode.CODE_30006); } // 极端场景下,sso-server 中心的单点注销可能并不会通知到当前 client 端,所以这里需要再补一刀 if (stpLogic.isLogin()) { stpLogic.logout(loginId, logoutParameter); } return SaSsoClientProcessor.instance._ssoLogoutBack(req, res); } }
Ruoyi-vue对接事件订阅
事件订阅主要用于做数据同步,对于历史项目来说,上线时需要考虑历史数据同步和新数据同步问题。事件订阅用于解决新数据同步。历史数据则需要根据具体的项目情况,自行线下同步。
在MDP平台配置“事件订阅”
在应用端开发“通知地址”接口,用于接收事件推送。
回调方法超时时间是5分钟,若你的业务比较复杂,请先存储事件日志后立即返回,然后异步处理事件的业务逻辑。若在5分钟内,MDP没有接收到返回,视为超时,会在之后的 2m,5m,30m,6h,12h发起重试,5次重试后就会停止重试。
入参固定格式:
@RequestBody String content,通过JSON.parseObject(content);解析后,格式如下:重点关注:method和biz_content。根据method的不同,biz_content也会不同,biz_content的格式遵循规则:
- 涉及单条数据时,格式为:
{id: 123}。比如:新增和修改时,推送组件ID,具体的业务数据还需要额外调用其他接口进行查询。 - 涉及多条数据时,格式为:
{ids: [11,22,33]}。比如:批量删除时,推送一个数据。
{ "app_key": "应用ID", "type": "EVENT_PUSH", // 回调类型,这里固定为EVENT_PUSH {EVENT_PUSH: 事件推送 CALLBACK: 接口回调} "format": "json", // 返回结果格式,JSON/XML,固定填:JSON "charset": "utf8", // 请求使用的编码格式 "sign_type": "RSA2", // 生成签名字符串所使用的签名算法类型 "timestamp": "2026-06-20 15:30:22", // 发送请求的时间,格式"yyyy-MM-dd HH:mm:ss" "method": "订阅的事件编码", "biz_content": "{\"id\":\"10001\"}", // 业务参数 "sign": "xxxxx" // 请求参数的签名串 }- 涉及单条数据时,格式为:
返回值固定格式:
{code: 0, msg: "错误原因"}
@RestController @RequestMapping("/callback") @Tag(name = "接收平台回调") public class CallbackController { private static final Logger log = LoggerFactory.getLogger(CallbackController.class); // MDP 开放平台服务(sop-gateway-server)地址,建议配置在yml static String url = "http://localhost:23456/api"; // 应用ID,建议配置在yml static String appId = "ruoyi-vue-sso"; // 平台公钥,建议配置在yml static String publicKey = "..."; /** * 开发者私钥,建议配置在yml */ static String privateKeyIsv = "..."; // 声明一个就行 static OpenClient client = new OpenClient(url, appId, privateKeyIsv, publicKey); @PostMapping("/notify") public Result<String> callback(@RequestBody String content) { log.info("收到回调通知, content={}", content); JSONObject jsonObject = JSON.parseObject(content); // 签名校验 if (!checkSign(jsonObject)) { return Result.error("签名校验错误"); } log.info("签名验证通过,处理业务逻辑"); String method = jsonObject.getString("method"); // 判断业务类型,处理不同业务 switch (method) { // 处理订单创建回调 case "user:add": addUser(jsonObject); break; case "org:add": addOrg(jsonObject); break; case "user:edit": editUser(jsonObject); break; case "user:delete": deleteUser(jsonObject); break; default: addUser(jsonObject); } return Result.success("ok"); } private boolean checkSign(JSONObject jsonObject) { try { return SignUtil.rsaCheckV2(jsonObject, publicKey, "UTF-8", SignUtil.RSA2); } catch (SopSignException e) { log.error("签名校验错误, jsonObject={}", jsonObject, e); return false; } } }添加依赖
<dependency> <groupId>top.mddata.sdk</groupId> <artifactId>mdp-simple-sdk</artifactId> <version>最新版本</version> </dependency>根据method,编写具体的业务代码
private Result<String> addUser(JSONObject jsonObject) { JSONObject bizContent = jsonObject.getJSONObject("biz_content"); log.info("业务参数,bizContent={}", bizContent); // MDP新增的 用户ID Long id = bizContent.getLong("id"); UserGetByIdApi param = new UserGetByIdApi(); IdRequest request = new IdRequest(); request.setId(id); param.setBizModel(request); // 调用 mdp-simple-sdk 提供的方法,获取数据 Result<UserResp> result = client.execute(param); if (result.isSuccess()) { UserResp response = result.getData(); SysUser sysUser = new SysUser(); sysUser.setSsoId(request.getId()); sysUser.setUserName(response.getUsername()); sysUser.setNickName(response.getName()); sysUser.setEmail(response.getEmail()); sysUser.setPhonenumber(response.getPhone()); sysUser.setStatus(response.getState() ? "0" : "1"); // 入库 sysUserService.insertUser(sysUser); return Result.success("ok"); } else { log.error("数据拉取失败,请确保开启了SopGatewayServerApplication和WorkerServerApplication"); return Result.error("数据拉取失败"); } } private void deleteUser(JSONObject jsonObject) { // 处理订单关闭回调 JSONObject bizContent = jsonObject.getJSONObject("biz_content"); log.info("业务参数,bizContent={}", bizContent); List<Long> ids = bizContent.getList("ids", Long.class); if (CollUtil.isNotEmpty(ids)) { sysUserService.deleteUserBySsoIds(ids); } }