From 811b3a6e9e584b5e85145707b8f220d1e3965943 Mon Sep 17 00:00:00 2001
From: liu <2021943741@qq.com>
Date: 星期二, 29 九月 2026 13:51:08 +0800
Subject: [PATCH] feat(wxcp): 新增企业微信模块,支持成员扫码登录、活动通知与通讯录

---
 yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/service/auth/AdminAuthServiceImpl.java |  105 +++++++++++++++++++++++++++++++++++++++++++++++-----
 1 files changed, 94 insertions(+), 11 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 1957b22..656dc96 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
@@ -17,10 +17,12 @@
 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.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;
@@ -35,10 +37,13 @@
 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.UUID;
 
 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
 import static cn.iocoder.yudao.framework.common.util.servlet.ServletUtils.getClientIP;
@@ -47,14 +52,21 @@
 /**
  * Auth Service 瀹炵幇绫�
  *
- * @author 鑺嬮亾婧愮爜
+ * @author 瓒呯骇绠$悊鍛�
  */
 @Service
 @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;
+
     @Resource
     private AdminUserService userService;
+    @Resource
+    private AdminUserMapper userMapper;
     @Resource
     private LoginLogService loginLogService;
     @Resource
@@ -69,6 +81,10 @@
     private CaptchaService captchaService;
     @Resource
     private SmsCodeApi smsCodeApi;
+    @Resource
+    private PasswordEncoder passwordEncoder;
+    @Resource
+    private ApplicationEventPublisher eventPublisher;
 
     /**
      * 楠岃瘉鐮佺殑寮�鍏筹紝榛樿涓� true
@@ -113,7 +129,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 +193,81 @@
     }
 
     @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());
-        if (user == null) {
-            throw exception(USER_NOT_EXISTS);
+        // 2. 鍒ゆ柇鏄惁宸叉湁缁戝畾鐨勭郴缁熺敤鎴�
+        Long bindUserId = socialUser.getUserId();
+        AdminUserDO user;
+
+        if (bindUserId == null) {
+            // 2.1 棣栨鐧诲綍锛氳嚜鍔ㄦ敞鍐屾柊鐢ㄦ埛
+            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());
+        } else {
+            // 2.2 宸叉湁缁戝畾锛氱洿鎺ヨ幏鍙栫敤鎴�
+            user = userService.getUser(bindUserId);
+            if (user == null) {
+                throw exception(USER_NOT_EXISTS);
+            }
         }
 
-        // 鍒涘缓 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);
+
+        return user;
     }
 
     @VisibleForTesting
@@ -303,4 +386,4 @@
 
         userService.updateUserPassword(userByMobile.getId(), reqVO.getPassword());
     }
-}
+}
\ No newline at end of file

--
Gitblit v1.9.3