From 1ee17464a9ef58ee9163d295298d0e40a0c1aee6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=91=A8=E9=B9=8F?= <812968653@qq.com> Date: Fri, 21 Aug 2026 20:07:29 +0800 Subject: [PATCH] =?UTF-8?q?bug=E4=BF=AE=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../app/user/AppMemberUserController.java | 2 +- .../web/config/MemberWebConfiguration.java | 16 +++++++++- .../service/user/MemberUserServiceImpl.java | 29 ++++++++++--------- 3 files changed, 32 insertions(+), 15 deletions(-) diff --git a/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/app/user/AppMemberUserController.java b/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/app/user/AppMemberUserController.java index 08cd36e..6996077 100644 --- a/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/app/user/AppMemberUserController.java +++ b/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/app/user/AppMemberUserController.java @@ -62,7 +62,7 @@ public class AppMemberUserController { @Operation(summary = "获得基本信息") public CommonResult getUserInfo() { MemberUserDO user = userService.getUser(getLoginUserId()); - // 禁用后兜底:即使 token 未清干净,拉资料时也强制踢下线 + // 禁用态已由 MemberUserDisableInterceptor 统一拦截;此处再兜底一次 if (user == null || CommonStatusEnum.isDisable(user.getStatus())) { if (user != null) { try { diff --git a/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/framework/web/config/MemberWebConfiguration.java b/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/framework/web/config/MemberWebConfiguration.java index 82c7003..850b7f8 100644 --- a/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/framework/web/config/MemberWebConfiguration.java +++ b/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/framework/web/config/MemberWebConfiguration.java @@ -1,9 +1,14 @@ package cn.iocoder.yudao.module.member.framework.web.config; import cn.iocoder.yudao.framework.swagger.config.YudaoSwaggerAutoConfiguration; +import cn.iocoder.yudao.module.member.framework.web.core.MemberUserDisableInterceptor; import org.springdoc.core.GroupedOpenApi; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.web.servlet.config.annotation.InterceptorRegistry; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; + +import javax.annotation.Resource; /** * member 模块的 web 组件的 Configuration @@ -11,7 +16,10 @@ import org.springframework.context.annotation.Configuration; * @author 芋道源码 */ @Configuration(proxyBeanMethods = false) -public class MemberWebConfiguration { +public class MemberWebConfiguration implements WebMvcConfigurer { + + @Resource + private MemberUserDisableInterceptor memberUserDisableInterceptor; /** * member 模块的 API 分组 @@ -21,4 +29,10 @@ public class MemberWebConfiguration { return YudaoSwaggerAutoConfiguration.buildGroupedOpenApi("member"); } + @Override + public void addInterceptors(InterceptorRegistry registry) { + // App 已登录请求统一校验禁用态(与个人资料页踢登录同一错误码) + registry.addInterceptor(memberUserDisableInterceptor).addPathPatterns("/**"); + } + } diff --git a/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/service/user/MemberUserServiceImpl.java b/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/service/user/MemberUserServiceImpl.java index 8991983..d1b23b8 100644 --- a/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/service/user/MemberUserServiceImpl.java +++ b/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/service/user/MemberUserServiceImpl.java @@ -11,6 +11,7 @@ import cn.iocoder.yudao.framework.common.util.object.BeanUtils; import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; import cn.iocoder.yudao.framework.tenant.core.aop.TenantIgnore; import cn.iocoder.yudao.module.member.client.service.ChatApi; +import cn.iocoder.yudao.module.member.client.vo.chat.privatemsg.ChatPrivateMessageSendResVO; import cn.iocoder.yudao.module.member.client.vo.chat.user.ChatCreateOrUpdateUserReqVO; import cn.iocoder.yudao.module.member.client.vo.chat.user.ChatUserOnLineStatusReqVo; import cn.iocoder.yudao.module.member.client.vo.chat.user.ChatUserOnLineStatusRespVo; @@ -478,9 +479,23 @@ public class MemberUserServiceImpl implements MemberUserService { } /** - * 清理会员全部 OAuth2 access + refresh,并通知 IM 立刻踢下线。 + * 清理会员全部 OAuth2 access + refresh,并通过 IM 私聊通知 App 踢登录(不封禁 IM 账号)。 */ private void kickMemberLogin(Long userId) { + // 先发 IM 消息(WS 仍在线时更容易送达),再清业务 token + try { + syncChatUser(userId); + // 约定前缀:Flutter 收到后先跳登录页,再清理本地态(不走 /third/user/ban) + ChatPrivateMessageSendResVO sent = chatApi.messageUserSendText( + userId, "__APP_KICK_SESSION__:账号已被禁用"); + if (sent == null) { + log.warn("禁用踢登录:IM 私聊通知未发出, userId={}", userId); + } else { + log.info("禁用踢登录:已发 IM 私聊通知, userId={}", userId); + } + } catch (Exception e) { + log.warn("禁用踢登录:IM 私聊通知失败, userId={}", userId, e); + } try { oauth2TokenApi.removeAccessTokenByUserId(userId, UserTypeEnum.MEMBER.getValue()); log.info("已清理会员登录 token, userId={}", userId); @@ -488,18 +503,6 @@ public class MemberUserServiceImpl implements MemberUserService { log.warn("踢出会员登录态失败, userId={}", userId, e); throw e; } - try { - // 确保 IM 侧有该用户,否则 /third/user/ban 会报「用户不存在」导致推送失败 - syncChatUser(userId); - boolean banned = chatApi.banUser(userId, "账号已被禁用"); - if (!banned) { - log.warn("通知聊天服务封禁用户失败(返回 false), userId={}", userId); - } else { - log.info("已通知聊天服务封禁并踢下线, userId={}", userId); - } - } catch (Exception e) { - log.warn("通知聊天服务封禁用户失败, userId={}", userId, e); - } } @VisibleForTesting