fix(auth): 企业微信扫码登录:原绑定用户被删除后按首次登录重新注册

system_social_user_bind 里的 user_id 可能指向「已被删除」的用户 ——
AdminUserServiceImpl.deleteUser 只清理了角色和岗位,没有清理这张社交绑定表,
删除后绑定关系会残留成孤儿。而这里原先只判断「有没有绑定」、不判断
「绑定的人还在不在」,于是该企业成员会永久卡在 USER_NOT_EXISTS:
既登不进来,也不会被重新注册,是一个无法自愈的死锁。

改为「绑定存在且用户仍存在」才算已绑定,否则走自动注册并改绑;
bindSocialUser 内部会先删掉该社交用户的旧绑定,改绑不会产生重复记录。

Co-Authored-By: Claude <noreply@anthropic.com>
已修改1个文件
25 ■■■■■ 文件已修改
yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/service/auth/AdminAuthServiceImpl.java 25 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/service/auth/AdminAuthServiceImpl.java
@@ -219,23 +219,30 @@
        }
        // 2. 判断是否已有绑定的系统用户
        //
        // 注意:system_social_user_bind 里的 user_id 可能指向「已被删除」的用户 ——
        // AdminUserServiceImpl.deleteUser 只清理了角色和岗位,没有清理这张社交绑定表,
        // 删除后绑定关系会残留成孤儿。所以这里不能只看「有没有绑定」,
        // 还要看「绑定的人还在不在」。
        Long bindUserId = socialUser.getUserId();
        AdminUserDO user;
        AdminUserDO user = bindUserId != null ? userService.getUser(bindUserId) : null;
        if (bindUserId == null) {
            // 2.1 首次登录:自动注册新用户
        if (user == null) {
            // 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());
        } else {
            // 2.2 已有绑定:直接获取用户
            user = userService.getUser(bindUserId);
            if (user == null) {
                throw exception(USER_NOT_EXISTS);
            }
        }
        // 3. 创建 Token 令牌,记录登录日志