feat(auth): 小程序登录采集微信昵称
This commit is contained in:
@@ -65,12 +65,14 @@ pub struct BindWechatPhoneInput {
|
||||
pub user_id: String,
|
||||
pub phone_number: String,
|
||||
pub verify_code: String,
|
||||
pub wechat_display_name: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
pub struct BindWechatVerifiedPhoneInput {
|
||||
pub user_id: String,
|
||||
pub phone_number: String,
|
||||
pub wechat_display_name: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
|
||||
@@ -111,11 +111,7 @@ fn hydrate_private_auth_fields(
|
||||
.find(|identity| identity.user_id == hydrated.user.id);
|
||||
if hydrated.user.wechat_display_name.is_none() {
|
||||
hydrated.user.wechat_display_name = hydrated_wechat_identity
|
||||
.and_then(|identity| identity.display_name.clone())
|
||||
.or_else(|| {
|
||||
(hydrated.user.login_method == AuthLoginMethod::Wechat)
|
||||
.then(|| hydrated.user.display_name.clone())
|
||||
});
|
||||
.and_then(|identity| normalize_optional_string(identity.display_name.clone()));
|
||||
}
|
||||
if hydrated.user.wechat_account.is_none() {
|
||||
hydrated.user.wechat_account =
|
||||
@@ -655,9 +651,11 @@ impl PhoneAuthService {
|
||||
return Err(PhoneAuthError::UserStateMismatch);
|
||||
}
|
||||
|
||||
let (merged_user, activated_new_user) = self
|
||||
.store
|
||||
.bind_wechat_phone_to_user(&input.user_id, normalized_phone)?;
|
||||
let (merged_user, activated_new_user) = self.store.bind_wechat_phone_to_user(
|
||||
&input.user_id,
|
||||
normalized_phone,
|
||||
input.wechat_display_name,
|
||||
)?;
|
||||
|
||||
Ok(BindWechatPhoneResult {
|
||||
user: merged_user,
|
||||
@@ -711,9 +709,11 @@ impl PhoneAuthService {
|
||||
return Err(PhoneAuthError::UserStateMismatch);
|
||||
}
|
||||
|
||||
let (merged_user, activated_new_user) = self
|
||||
.store
|
||||
.bind_wechat_phone_to_user(&input.user_id, normalized_phone)?;
|
||||
let (merged_user, activated_new_user) = self.store.bind_wechat_phone_to_user(
|
||||
&input.user_id,
|
||||
normalized_phone,
|
||||
input.wechat_display_name,
|
||||
)?;
|
||||
|
||||
Ok(BindWechatPhoneResult {
|
||||
user: merged_user,
|
||||
@@ -1365,8 +1365,7 @@ impl InMemoryAuthStore {
|
||||
.filter(|value| !value.is_empty())
|
||||
.unwrap_or("微信旅人")
|
||||
.to_string();
|
||||
let wechat_display_name = normalize_optional_string(profile.display_name.clone())
|
||||
.or_else(|| Some(display_name.clone()));
|
||||
let wechat_display_name = normalize_optional_string(profile.display_name.clone());
|
||||
let username = build_wechat_username(&display_name, &profile.provider_uid);
|
||||
let provider_uid = normalize_required_string(&profile.provider_uid).unwrap_or_default();
|
||||
let user = AuthUser {
|
||||
@@ -1758,11 +1757,13 @@ impl InMemoryAuthStore {
|
||||
&self,
|
||||
pending_user_id: &str,
|
||||
phone_number: PhoneNumberSnapshot,
|
||||
wechat_display_name: Option<String>,
|
||||
) -> Result<(AuthUser, bool), PhoneAuthError> {
|
||||
let mut state = self
|
||||
.inner
|
||||
.lock()
|
||||
.map_err(|_| PhoneAuthError::Store("用户仓储锁已中毒".to_string()))?;
|
||||
let submitted_wechat_display_name = normalize_optional_string(wechat_display_name);
|
||||
|
||||
let existing_phone_user_id =
|
||||
Self::resolve_phone_user_locked(&mut state, &phone_number.e164)
|
||||
@@ -1777,20 +1778,24 @@ impl InMemoryAuthStore {
|
||||
.cloned()
|
||||
.ok_or(PhoneAuthError::UserStateMismatch)?;
|
||||
let pending_wechat_account = pending_wechat_identity.provider_uid.clone();
|
||||
let pending_wechat_display_name = pending_wechat_identity.display_name.clone();
|
||||
|
||||
let pending_username = state
|
||||
let pending_user = state
|
||||
.users_by_username
|
||||
.values()
|
||||
.find(|stored| stored.user.id == pending_user_id)
|
||||
.map(|stored| stored.user.username.clone())
|
||||
.cloned()
|
||||
.ok_or(PhoneAuthError::UserNotFound)?;
|
||||
let pending_username = pending_user.user.username.clone();
|
||||
let pending_wechat_display_name = submitted_wechat_display_name
|
||||
.clone()
|
||||
.or_else(|| normalize_optional_string(pending_wechat_identity.display_name.clone()))
|
||||
.or_else(|| normalize_optional_string(pending_user.user.wechat_display_name));
|
||||
state.users_by_username.remove(&pending_username);
|
||||
|
||||
state.wechat_identity_by_provider_uid.insert(
|
||||
pending_wechat_identity.provider_uid.clone(),
|
||||
StoredWechatIdentity {
|
||||
user_id: target_user_id.clone(),
|
||||
display_name: pending_wechat_display_name.clone(),
|
||||
..pending_wechat_identity.clone()
|
||||
},
|
||||
);
|
||||
@@ -1825,11 +1830,31 @@ impl InMemoryAuthStore {
|
||||
.values()
|
||||
.find(|identity| identity.user_id == pending_user_id)
|
||||
.map(|identity| identity.provider_uid.clone());
|
||||
let bound_wechat_display_name = state
|
||||
.wechat_identity_by_provider_uid
|
||||
.values()
|
||||
.find(|identity| identity.user_id == pending_user_id)
|
||||
.and_then(|identity| identity.display_name.clone());
|
||||
let bound_wechat_display_name = submitted_wechat_display_name.clone().or_else(|| {
|
||||
state
|
||||
.wechat_identity_by_provider_uid
|
||||
.values()
|
||||
.find(|identity| identity.user_id == pending_user_id)
|
||||
.and_then(|identity| normalize_optional_string(identity.display_name.clone()))
|
||||
.or_else(|| {
|
||||
state
|
||||
.users_by_username
|
||||
.values()
|
||||
.find(|stored| stored.user.id == pending_user_id)
|
||||
.and_then(|stored| {
|
||||
normalize_optional_string(stored.user.wechat_display_name.clone())
|
||||
})
|
||||
})
|
||||
});
|
||||
|
||||
if let Some(display_name) = bound_wechat_display_name.clone()
|
||||
&& let Some(identity) = state
|
||||
.wechat_identity_by_provider_uid
|
||||
.values_mut()
|
||||
.find(|identity| identity.user_id == pending_user_id)
|
||||
{
|
||||
identity.display_name = Some(display_name);
|
||||
}
|
||||
|
||||
let stored_user = state
|
||||
.users_by_username
|
||||
@@ -3584,6 +3609,7 @@ mod tests {
|
||||
user_id: wechat_user.id.clone(),
|
||||
phone_number: "13800138000".to_string(),
|
||||
verify_code: "123456".to_string(),
|
||||
wechat_display_name: None,
|
||||
},
|
||||
now + Duration::seconds(3),
|
||||
)
|
||||
@@ -3619,4 +3645,97 @@ mod tests {
|
||||
Some("已归并微信用户")
|
||||
);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn bind_wechat_phone_keeps_account_marker_when_identity_has_no_display_name() {
|
||||
let store = build_store();
|
||||
let phone_service = build_phone_service(store.clone());
|
||||
let wechat_service = WechatAuthService::new(store.clone());
|
||||
let now = OffsetDateTime::now_utc();
|
||||
|
||||
phone_service
|
||||
.send_code(
|
||||
SendPhoneCodeInput {
|
||||
phone_number: "13800138031".to_string(),
|
||||
scene: PhoneAuthScene::Login,
|
||||
},
|
||||
now,
|
||||
)
|
||||
.await
|
||||
.expect("phone login code should send");
|
||||
let phone_user = phone_service
|
||||
.login(
|
||||
PhoneLoginInput {
|
||||
phone_number: "13800138031".to_string(),
|
||||
verify_code: "123456".to_string(),
|
||||
},
|
||||
now + Duration::seconds(1),
|
||||
)
|
||||
.await
|
||||
.expect("phone login should succeed")
|
||||
.user;
|
||||
|
||||
let wechat_user = wechat_service
|
||||
.resolve_login(ResolveWechatLoginInput {
|
||||
profile: WechatIdentityProfile {
|
||||
provider_uid: "wx-openid-mini-bind".to_string(),
|
||||
provider_union_id: Some("wx-union-mini-bind".to_string()),
|
||||
display_name: None,
|
||||
avatar_url: None,
|
||||
session_key: Some("mini-session-key".to_string()),
|
||||
},
|
||||
})
|
||||
.await
|
||||
.expect("mini program wechat login should succeed")
|
||||
.user;
|
||||
|
||||
assert_eq!(wechat_user.wechat_display_name, None);
|
||||
assert_eq!(
|
||||
wechat_user.wechat_account.as_deref(),
|
||||
Some("wx-openid-mini-bind")
|
||||
);
|
||||
assert_ne!(wechat_user.id, phone_user.id);
|
||||
|
||||
phone_service
|
||||
.send_code(
|
||||
SendPhoneCodeInput {
|
||||
phone_number: "13800138031".to_string(),
|
||||
scene: PhoneAuthScene::BindPhone,
|
||||
},
|
||||
now + Duration::seconds(2),
|
||||
)
|
||||
.await
|
||||
.expect("bind phone code should send");
|
||||
let merged = phone_service
|
||||
.bind_wechat_phone(
|
||||
BindWechatPhoneInput {
|
||||
user_id: wechat_user.id.clone(),
|
||||
phone_number: "13800138031".to_string(),
|
||||
verify_code: "123456".to_string(),
|
||||
wechat_display_name: None,
|
||||
},
|
||||
now + Duration::seconds(3),
|
||||
)
|
||||
.await
|
||||
.expect("bind phone should succeed");
|
||||
|
||||
assert_eq!(merged.user.id, phone_user.id);
|
||||
assert!(merged.user.wechat_bound);
|
||||
assert_eq!(merged.user.wechat_display_name, None);
|
||||
assert_eq!(
|
||||
merged.user.wechat_account.as_deref(),
|
||||
Some("wx-openid-mini-bind")
|
||||
);
|
||||
|
||||
let restored_user = build_password_service(store)
|
||||
.get_user_by_id(&phone_user.id)
|
||||
.expect("user lookup should succeed")
|
||||
.expect("merged user should exist")
|
||||
.user;
|
||||
assert_eq!(restored_user.wechat_display_name, None);
|
||||
assert_eq!(
|
||||
restored_user.wechat_account.as_deref(),
|
||||
Some("wx-openid-mini-bind")
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user