Browse Source

refactor(auth): deduplicate user location logic in login flow

Extract locateUser() as the single source of truth for 'identity binding ->
mobile match' resolution. Both preCheckOrgMembership (read-only probe) and
resolveUser (login path) now share the same implementation, eliminating the
risk of rule drift between the two call sites.

Identity query is passed through to avoid redundant DB lookups.
master
luoweijian 1 month ago
parent
commit
f0f70c6137
  1. 74
      crm-auth/src/main/java/com/crm/auth/service/impl/AuthServiceImpl.java

74
crm-auth/src/main/java/com/crm/auth/service/impl/AuthServiceImpl.java

@ -115,33 +115,20 @@ public class AuthServiceImpl implements IAuthService {
* <p>组织准入校验ADR-0010 login() 在事务外预校验完成本方法不再调钉钉 API</p> * <p>组织准入校验ADR-0010 login() 在事务外预校验完成本方法不再调钉钉 API</p>
*/ */
private AuthUser resolveUser(IdentityTypeEnum type, ThirdPartyUserInfo thirdUser) { private AuthUser resolveUser(IdentityTypeEnum type, ThirdPartyUserInfo thirdUser) {
// 2.1 该三方身份已绑定过,直接取对应用户 // 身份查询只做一次,供定位与绑定共用
AuthIdentity identity = authIdentityService.getByTypeAndUnionId(type, thirdUser.getUnionId()); AuthIdentity identity = authIdentityService.getByTypeAndUnionId(type, thirdUser.getUnionId());
if (identity != null) { AuthUser user = locateUser(type, thirdUser, identity);
AuthUser existUser = authUserService.getById(identity.getUserId());
if (existUser != null) { // 仍无匹配 -> 首登自动注册(组织准入已由 login() 的事务外预校验保证)
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() 的事务外预校验保证)
if (user == null) { if (user == null) {
user = registerNewUser(thirdUser); user = registerNewUser(thirdUser);
} }
// 2.4 处理身份绑定:孤儿身份重定向到新用户;无身份则新增 // 处理身份绑定:孤儿身份重定向到新用户;无身份则新增
if (identity == null) { if (identity == null) {
authIdentityService.bind(user.getId(), type, thirdUser); authIdentityService.bind(user.getId(), type, thirdUser);
} else { } else if (!identity.getUserId().equals(user.getId())) {
// 孤儿 identity:把原本指向已删除用户的绑定,重定向到本次定位到的用户,避免下次登录再次命中孤儿 // 孤儿 Identity:把原本指向已删除用户的绑定,重定向到本次定位到的用户
AuthIdentity redirect = new AuthIdentity(); AuthIdentity redirect = new AuthIdentity();
redirect.setId(identity.getId()); redirect.setId(identity.getId());
redirect.setUserId(user.getId()); redirect.setUserId(user.getId());
@ -150,6 +137,32 @@ public class AuthServiceImpl implements IAuthService {
} }
return user; return user;
} }
/**
* 定位本地用户已绑定身份 -> 手机号匹配
* <p> {@link #preCheckOrgMembership} 的只读探测和 {@link #resolveUser} 的登录定位共用
* 确保身份绑定 手机号匹配的规则只写一遍避免两处逻辑漂移</p>
*
* @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本地已有匹配用户的登录不校验 * 事务外组织准入预校验ADR-0010本地已有匹配用户的登录不校验
@ -157,27 +170,14 @@ public class AuthServiceImpl implements IAuthService {
* <p>事务内注册路径的组织门禁由此处保证login() doLoginInTx 的唯一入口</p> * <p>事务内注册路径的组织门禁由此处保证login() doLoginInTx 的唯一入口</p>
*/ */
private void preCheckOrgMembership(IdentityTypeEnum type, ThirdPartyUserInfo thirdUser, ThirdPartyAuthClient client) { 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; return;
} }
verifyOrgMembership(client, thirdUser); 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 中的用户不受影响 * 组织准入校验ADR-0010非本组织成员拒绝登录仅在首登注册前触发已在 DB 中的用户不受影响
*/ */

Loading…
Cancel
Save