@ -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 ( ) ) ) {
// 孤儿 i dentity:把原本指向已删除用户的绑定,重定向到本次定位到的用户,避免下次登录再次命中孤儿
// 孤儿 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 中的用户不受影响 。
* /
* /