From 6b5b38a8dbdb02036d1de361334b51efc8d61d2a Mon Sep 17 00:00:00 2001
From: liu <2021943741@qq.com>
Date: 星期三, 30 九月 2026 15:26:05 +0800
Subject: [PATCH] fix(auth): 企业微信扫码登录:原绑定用户被删除后按首次登录重新注册
---
yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/service/auth/AdminAuthServiceImpl.java | 150 +++++++++++++++++++++++++++++++++++++++++++++++---
1 files changed, 141 insertions(+), 9 deletions(-)
diff --git a/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/service/auth/AdminAuthServiceImpl.java b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/service/auth/AdminAuthServiceImpl.java
index a36b7d9..72de06f 100644
--- a/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/service/auth/AdminAuthServiceImpl.java
+++ b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/service/auth/AdminAuthServiceImpl.java
@@ -16,14 +16,19 @@
import cn.iocoder.yudao.module.system.controller.admin.auth.vo.*;
import cn.iocoder.yudao.module.system.convert.auth.AuthConvert;
import cn.iocoder.yudao.module.system.dal.dataobject.oauth2.OAuth2AccessTokenDO;
+import cn.iocoder.yudao.module.system.dal.dataobject.permission.RoleDO;
import cn.iocoder.yudao.module.system.dal.dataobject.user.AdminUserDO;
+import cn.iocoder.yudao.module.system.dal.mysql.user.AdminUserMapper;
import cn.iocoder.yudao.module.system.enums.logger.LoginLogTypeEnum;
import cn.iocoder.yudao.module.system.enums.logger.LoginResultEnum;
import cn.iocoder.yudao.module.system.enums.oauth2.OAuth2ClientConstants;
import cn.iocoder.yudao.module.system.enums.sms.SmsSceneEnum;
+import cn.iocoder.yudao.module.system.event.SocialLoginEvent;
import cn.iocoder.yudao.module.system.service.logger.LoginLogService;
import cn.iocoder.yudao.module.system.service.member.MemberService;
import cn.iocoder.yudao.module.system.service.oauth2.OAuth2TokenService;
+import cn.iocoder.yudao.module.system.service.permission.PermissionService;
+import cn.iocoder.yudao.module.system.service.permission.RoleService;
import cn.iocoder.yudao.module.system.service.social.SocialUserService;
import cn.iocoder.yudao.module.system.service.user.AdminUserService;
import com.anji.captcha.model.common.ResponseModel;
@@ -35,10 +40,14 @@
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
+import org.springframework.context.ApplicationEventPublisher;
+import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.Objects;
+import java.util.Set;
+import java.util.UUID;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.framework.common.util.servlet.ServletUtils.getClientIP;
@@ -53,8 +62,23 @@
@Slf4j
public class AdminAuthServiceImpl implements AdminAuthService {
+ /**
+ * 浼佷笟寰俊绀句氦绫诲瀷锛屽搴� {@link cn.iocoder.yudao.module.system.enums.social.SocialTypeEnum#WECHAT_ENTERPRISE}
+ */
+ private static final Integer WECHAT_ENTERPRISE_TYPE = 30;
+
+ /**
+ * 浼佷笟寰俊鎵爜鑷姩娉ㄥ唽鐨勮处鍙凤紝榛樿缁戝畾鐨勮鑹茬紪鐮併��
+ *
+ * 闇�瑕佸湪銆岀郴缁熺鐞� 鈫� 瑙掕壊绠$悊銆嶉噷寤哄ソ璇ョ紪鐮佺殑瑙掕壊骞跺嬀閫夎彍鍗曪紝鍚﹀垯鏂拌处鍙风櫥褰曞悗娌℃湁浠讳綍鑿滃崟銆�
+ * 缂栫爜鑰岄潪瑙掕壊缂栧彿锛氳鑹茬紪鍙峰湪鏈湴/娴嬭瘯/鐢熶骇鍚勫簱涓嶄竴鑷达紝鍐欐浼氬湪鎹㈠簱鍚庨潤榛樺け鏁堛��
+ */
+ private static final String WXCP_DEFAULT_ROLE_CODE = "wxcp_user";
+
@Resource
private AdminUserService userService;
+ @Resource
+ private AdminUserMapper userMapper;
@Resource
private LoginLogService loginLogService;
@Resource
@@ -69,6 +93,14 @@
private CaptchaService captchaService;
@Resource
private SmsCodeApi smsCodeApi;
+ @Resource
+ private PasswordEncoder passwordEncoder;
+ @Resource
+ private ApplicationEventPublisher eventPublisher;
+ @Resource
+ private RoleService roleService;
+ @Resource
+ private PermissionService permissionService;
/**
* 楠岃瘉鐮佺殑寮�鍏筹紝榛樿涓� true
@@ -113,7 +145,15 @@
reqVO.getSocialType(), reqVO.getSocialCode(), reqVO.getSocialState()));
}
// 鍒涘缓 Token 浠ょ墝锛岃褰曠櫥褰曟棩蹇�
- return createTokenAfterLoginSuccess(user.getId(), reqVO.getUsername(), LoginLogTypeEnum.LOGIN_USERNAME);
+ AuthLoginRespVO result = createTokenAfterLoginSuccess(user.getId(), reqVO.getUsername(), LoginLogTypeEnum.LOGIN_USERNAME);
+
+ // 鍙戝竷绀句氦鐧诲綍浜嬩欢锛堢粦瀹氭柊绀句氦璐﹀彿鏃讹級
+ if (reqVO.getSocialType() != null) {
+ eventPublisher.publishEvent(new SocialLoginEvent(
+ reqVO.getSocialType(), user.getId(), user.getUsername(), "璐﹀彿瀵嗙爜缁戝畾"));
+ }
+
+ return result;
}
@Override
@@ -169,22 +209,114 @@
}
@Override
+ @Transactional(rollbackFor = Exception.class)
public AuthLoginRespVO socialLogin(AuthSocialLoginReqVO reqVO) {
- // 浣跨敤 code 鎺堟潈鐮侊紝杩涜鐧诲綍銆傜劧鍚庯紝鑾峰緱鍒扮粦瀹氱殑鐢ㄦ埛缂栧彿
+ // 1. 浣跨敤 code 鎺堟潈鐮侊紝鑾峰彇绀句氦鐢ㄦ埛淇℃伅
SocialUserRespDTO socialUser = socialUserService.getSocialUserByCode(UserTypeEnum.ADMIN.getValue(), reqVO.getType(),
reqVO.getCode(), reqVO.getState());
- if (socialUser == null || socialUser.getUserId() == null) {
+ if (socialUser == null) {
throw exception(AUTH_THIRD_LOGIN_NOT_BIND);
}
- // 鑾峰緱鐢ㄦ埛
- AdminUserDO user = userService.getUser(socialUser.getUserId());
+ // 2. 鍒ゆ柇鏄惁宸叉湁缁戝畾鐨勭郴缁熺敤鎴�
+ //
+ // 娉ㄦ剰锛歴ystem_social_user_bind 閲岀殑 user_id 鍙兘鎸囧悜銆屽凡琚垹闄ゃ�嶇殑鐢ㄦ埛 鈥斺��
+ // AdminUserServiceImpl.deleteUser 鍙竻鐞嗕簡瑙掕壊鍜屽矖浣嶏紝娌℃湁娓呯悊杩欏紶绀句氦缁戝畾琛紝
+ // 鍒犻櫎鍚庣粦瀹氬叧绯讳細娈嬬暀鎴愬鍎裤�傛墍浠ヨ繖閲屼笉鑳藉彧鐪嬨�屾湁娌℃湁缁戝畾銆嶏紝
+ // 杩樿鐪嬨�岀粦瀹氱殑浜鸿繕鍦ㄤ笉鍦ㄣ�嶃��
+ Long bindUserId = socialUser.getUserId();
+ AdminUserDO user = bindUserId != null ? userService.getUser(bindUserId) : null;
+
if (user == null) {
- throw exception(USER_NOT_EXISTS);
+ // 2.1 棣栨鐧诲綍锛屾垨鍘熺粦瀹氱敤鎴峰凡琚垹闄わ細鑷姩娉ㄥ唽鏂扮敤鎴峰苟锛堟敼锛夌粦瀹�
+ //
+ // 鍘熺粦瀹氱敤鎴峰凡鍒犻櫎鏃跺繀椤昏蛋杩欐潯璺細鍚﹀垯璇ヤ紒涓氭垚鍛樹細姘镐箙鍗″湪銆岀敤鎴蜂笉瀛樺湪銆嶁�斺��
+ // 鏃㈢櫥涓嶈繘鏉ワ紝涔熶笉浼氳閲嶆柊娉ㄥ唽锛屾槸涓�涓棤娉曡嚜鎰堢殑姝婚攣銆�
+ // bindSocialUser 鍐呴儴浼氬厛鍒犳帀璇ョぞ浜ょ敤鎴风殑鏃х粦瀹氾紝鎵�浠ユ敼缁戜笉浼氫骇鐢熼噸澶嶈褰曘��
+ if (bindUserId != null) {
+ log.warn("[socialLogin][绀句氦鐢ㄦ埛({}) 鍘熺粦瀹氱殑鐢ㄦ埛({}) 宸蹭笉瀛樺湪锛堝彲鑳藉凡琚垹闄わ級锛屾寜棣栨鐧诲綍閲嶆柊娉ㄥ唽]",
+ socialUser.getOpenid(), bindUserId);
+ }
+ user = autoRegisterUser(socialUser, reqVO.getType());
+ // 缁戝畾绀句氦璐﹀彿
+ socialUserService.bindSocialUser(new SocialUserBindReqDTO(user.getId(), getUserType().getValue(),
+ reqVO.getType(), reqVO.getCode(), reqVO.getState()));
+ log.info("[socialLogin][绀句氦鐧诲綍鑷姩娉ㄥ唽 userId={} username={} socialType={}]",
+ user.getId(), user.getUsername(), reqVO.getType());
}
- // 鍒涘缓 Token 浠ょ墝锛岃褰曠櫥褰曟棩蹇�
- return createTokenAfterLoginSuccess(user.getId(), user.getUsername(), LoginLogTypeEnum.LOGIN_SOCIAL);
+ // 3. 鍒涘缓 Token 浠ょ墝锛岃褰曠櫥褰曟棩蹇�
+ AuthLoginRespVO result = createTokenAfterLoginSuccess(user.getId(), user.getUsername(), LoginLogTypeEnum.LOGIN_SOCIAL);
+
+ // 4. 鍙戝竷绀句氦鐧诲綍浜嬩欢锛堜緵鍏朵粬妯″潡鐩戝惉锛屽鍙戦�佷紒涓氬井淇¢�氱煡锛�
+ eventPublisher.publishEvent(new SocialLoginEvent(
+ reqVO.getType(), user.getId(), user.getUsername(), "绀句氦鎵爜"));
+
+ return result;
+ }
+
+ /**
+ * 绀句氦鐧诲綍鑷姩娉ㄥ唽鐢ㄦ埛
+ *
+ * 褰撶敤鎴烽娆¢�氳繃绀句氦璐﹀彿锛堝浼佷笟寰俊锛夋壂鐮佷笖鏈粦瀹氭椂锛岃嚜鍔ㄥ垱寤虹郴缁熺敤鎴�
+ *
+ * @param socialUser 绀句氦鐢ㄦ埛淇℃伅
+ * @param socialType 绀句氦绫诲瀷
+ * @return 鏂板垱寤虹殑鐢ㄦ埛
+ */
+ private AdminUserDO autoRegisterUser(SocialUserRespDTO socialUser, Integer socialType) {
+ // 1. 鑷姩鐢熸垚鐢ㄦ埛鍚嶏紙wx_ + 8浣嶉殢鏈哄崄鍏繘鍒讹級
+ String rawUsername = "wx_" + UUID.randomUUID().toString().replaceAll("-", "").substring(0, 8);
+
+ // 2. 纭繚鐢ㄦ埛鍚嶅敮涓�锛堝鏋滃啿绐佸垯閲嶈瘯锛�
+ String username = rawUsername;
+ int retry = 0;
+ while (userService.getUserByUsername(username) != null && retry < 5) {
+ username = "wx_" + UUID.randomUUID().toString().replaceAll("-", "").substring(0, 8);
+ retry++;
+ }
+ if (retry >= 5) {
+ throw exception(USER_USERNAME_EXISTS);
+ }
+
+ // 3. 鐢熸垚闅忔満瀵嗙爜
+ String password = UUID.randomUUID().toString().replaceAll("-", "").substring(0, 16);
+
+ // 4. 鍒涘缓鐢ㄦ埛
+ AdminUserDO user = new AdminUserDO();
+ user.setUsername(username);
+ user.setNickname(socialUser.getNickname() != null ? socialUser.getNickname() : username);
+ user.setPassword(passwordEncoder.encode(password));
+ user.setStatus(CommonStatusEnum.ENABLE.getStatus());
+ userMapper.insert(user);
+
+ // 5. 缁戝畾榛樿瑙掕壊
+ // 涓嶇粦鐨勮瘽璐﹀彿鑳界櫥褰曪紝浣� get-permission-info 杩斿洖绌鸿彍鍗曪紝杩涘幓涓�鐗囩┖鐧斤紱
+ // 杩欑"鑳借繘浣嗕粈涔堥兘鐪嬩笉鍒�"鐨勭姸鎬佷笉浼氭姤閿欙紝寰堥毦瀹氫綅锛屾墍浠ユ敞鍐屾椂灏辩粦涓�
+ bindDefaultRole(user);
+
+ return user;
+ }
+
+ /**
+ * 缁欒嚜鍔ㄦ敞鍐岀殑璐﹀彿缁戝畾榛樿瑙掕壊
+ *
+ * 瑙掕壊涓嶅瓨鍦ㄦ椂鍙墦璀﹀憡銆佷笉鎶涘紓甯革細涓�涓厤缃仐婕忎笉搴旇璁╂壂鐮佺櫥褰曟暣鏉¢摼璺笉鍙敤锛�
+ * 鑰屼笖璀﹀憡鏃ュ織閲屽凡缁忓啓鏄庝簡鍘诲摢鍎胯ˉ銆�
+ *
+ * @param user 鑷姩娉ㄥ唽鍑烘潵鐨勭敤鎴�
+ */
+ private void bindDefaultRole(AdminUserDO user) {
+ RoleDO role = roleService.getRoleByCode(WXCP_DEFAULT_ROLE_CODE);
+ if (role == null) {
+ log.warn("[bindDefaultRole][瑙掕壊缂栫爜({}) 涓嶅瓨鍦紝鐢ㄦ埛({}) 灏嗘病鏈変换浣曡彍鍗曟潈闄愶紱" +
+ "璇峰湪銆岀郴缁熺鐞� 鈫� 瑙掕壊绠$悊銆嶆柊寤虹紪鐮佷负 {} 鐨勮鑹插苟鍒嗛厤鑿滃崟]",
+ WXCP_DEFAULT_ROLE_CODE, user.getUsername(), WXCP_DEFAULT_ROLE_CODE);
+ return;
+ }
+ permissionService.assignUserRole(user.getId(), Set.of(role.getId()));
+ log.info("[bindDefaultRole][鐢ㄦ埛({}) 宸茬粦瀹氶粯璁よ鑹�({}/{})]",
+ user.getUsername(), role.getCode(), role.getName());
}
@VisibleForTesting
@@ -303,4 +435,4 @@
userService.updateUserPassword(userByMobile.getId(), reqVO.getPassword());
}
-}
+}
\ No newline at end of file
--
Gitblit v1.9.3