diff --git a/crm-auth/src/main/java/com/crm/auth/service/impl/AuthServiceImpl.java b/crm-auth/src/main/java/com/crm/auth/service/impl/AuthServiceImpl.java index 4346d4a..90e6670 100644 --- a/crm-auth/src/main/java/com/crm/auth/service/impl/AuthServiceImpl.java +++ b/crm-auth/src/main/java/com/crm/auth/service/impl/AuthServiceImpl.java @@ -115,33 +115,20 @@ public class AuthServiceImpl implements IAuthService { *
组织准入校验(ADR-0010)由 login() 在事务外预校验完成,本方法不再调钉钉 API。
*/ private AuthUser resolveUser(IdentityTypeEnum type, ThirdPartyUserInfo thirdUser) { - // 2.1 该三方身份已绑定过,直接取对应用户 + // 身份查询只做一次,供定位与绑定共用 AuthIdentity identity = authIdentityService.getByTypeAndUnionId(type, thirdUser.getUnionId()); - if (identity != null) { - AuthUser existUser = authUserService.getById(identity.getUserId()); - if (existUser != null) { - return existUser; - } - // 极端情况:身份存在但用户被物理删除,兜底走注册 - log.warn("身份绑定[{}]指向的用户[{}]不存在,将重新注册", identity.getId(), identity.getUserId()); - } - - // 2.2 按手机号匹配已有用户(跨平台身份合一的关键) - AuthUser user = null; - if (StrUtil.isNotBlank(thirdUser.getMobile())) { - user = authUserService.getByMobile(thirdUser.getMobile()); - } - - // 2.3 仍无匹配 -> 首登自动注册(组织准入已由 login() 的事务外预校验保证) + AuthUser user = locateUser(type, thirdUser, identity); + + // 仍无匹配 -> 首登自动注册(组织准入已由 login() 的事务外预校验保证) if (user == null) { user = registerNewUser(thirdUser); } - - // 2.4 处理身份绑定:孤儿身份重定向到新用户;无身份则新增 + + // 处理身份绑定:孤儿身份重定向到新用户;无身份则新增 if (identity == null) { authIdentityService.bind(user.getId(), type, thirdUser); - } else { - // 孤儿 identity:把原本指向已删除用户的绑定,重定向到本次定位到的用户,避免下次登录再次命中孤儿 + } else if (!identity.getUserId().equals(user.getId())) { + // 孤儿 Identity:把原本指向已删除用户的绑定,重定向到本次定位到的用户 AuthIdentity redirect = new AuthIdentity(); redirect.setId(identity.getId()); redirect.setUserId(user.getId()); @@ -150,6 +137,32 @@ public class AuthServiceImpl implements IAuthService { } return user; } + + /** + * 定位本地用户:已绑定身份 -> 手机号匹配。 + *供 {@link #preCheckOrgMembership} 的只读探测和 {@link #resolveUser} 的登录定位共用, + * 确保「身份绑定 → 手机号匹配」的规则只写一遍,避免两处逻辑漂移。
+ * + * @param identity 已查询的身份绑定记录(可为 null),避免重复查询 + * @return 匹配到的用户;无匹配返回 null + */ + private AuthUser locateUser(IdentityTypeEnum type, ThirdPartyUserInfo thirdUser, AuthIdentity identity) { + // 1. 该三方身份已绑定过,直接取对应用户 + if (identity != null) { + AuthUser existUser = authUserService.getById(identity.getUserId()); + if (existUser != null) { + return existUser; + } + // 极端情况:身份存在但用户被物理删除,兜底走注册 + log.warn("身份绑定[{}]指向的用户[{}]不存在,将重新注册", identity.getId(), identity.getUserId()); + } + + // 2. 按手机号匹配已有用户(跨平台身份合一的关键) + if (StrUtil.isNotBlank(thirdUser.getMobile())) { + return authUserService.getByMobile(thirdUser.getMobile()); + } + return null; + } /** * 事务外组织准入预校验(ADR-0010):本地已有匹配用户的登录不校验; @@ -157,27 +170,14 @@ public class AuthServiceImpl implements IAuthService { *事务内注册路径的组织门禁由此处保证(login() 是 doLoginInTx 的唯一入口)。
*/ private void preCheckOrgMembership(IdentityTypeEnum type, ThirdPartyUserInfo thirdUser, ThirdPartyAuthClient client) { - if (hasLocalUser(type, thirdUser)) { + // 只读探测:identity 查询一次,无缓存复用(事务外调用,与事务内 resolveUser 的查询独立) + AuthIdentity identity = authIdentityService.getByTypeAndUnionId(type, thirdUser.getUnionId()); + if (locateUser(type, thirdUser, identity) != null) { return; } verifyOrgMembership(client, thirdUser); } - /** - * 只读探测本地是否已有匹配用户(与 resolveUser 的定位规则一致,仅用于决定是否触发组织准入校验) - */ - private boolean hasLocalUser(IdentityTypeEnum type, ThirdPartyUserInfo thirdUser) { - AuthIdentity identity = authIdentityService.getByTypeAndUnionId(type, thirdUser.getUnionId()); - if (identity != null) { - AuthUser existUser = authUserService.getById(identity.getUserId()); - if (existUser != null) { - return true; - } - } - return StrUtil.isNotBlank(thirdUser.getMobile()) - && authUserService.getByMobile(thirdUser.getMobile()) != null; - } - /** * 组织准入校验(ADR-0010):非本组织成员拒绝登录。仅在首登注册前触发,已在 DB 中的用户不受影响。 */