收紧微信手机号响应非空契约

按微信官方响应文档将 phoneNumber、purePhoneNumber、countryCode 设为必填字段
补充字段缺失、错误响应和空字符串的失败关闭测试
This commit is contained in:
2026-07-23 13:34:57 +08:00
parent 3ad79572ba
commit 2a80fa179a
+88 -27
View File
@@ -362,17 +362,45 @@ struct WechatPhoneNumberResponse {
phone_info: Option<WechatPhoneNumberInfo>,
}
// 微信成功响应按官方文档必须包含这三个字段:
// https://developers.weixin.qq.com/miniprogram/dev/server/API/user-info/phone-number/api_getphonenumber.html#Res-phone-info-Object-Payload
#[derive(Debug, Deserialize)]
struct WechatPhoneNumberInfo {
#[serde(default)]
#[serde(alias = "phoneNumber")]
phone_number: Option<String>,
#[serde(default)]
#[serde(alias = "purePhoneNumber")]
pure_phone_number: Option<String>,
#[serde(default)]
#[serde(alias = "countryCode")]
country_code: Option<String>,
#[serde(rename = "phoneNumber")]
phone_number: String,
#[serde(rename = "purePhoneNumber")]
pure_phone_number: String,
#[serde(rename = "countryCode")]
country_code: String,
}
fn normalize_wechat_phone_number_info(
phone_info: WechatPhoneNumberInfo,
) -> Result<WechatPhoneNumberProfile, WechatProviderError> {
let pure_phone_number = phone_info.pure_phone_number.trim();
if pure_phone_number.is_empty() {
return Err(WechatProviderError::MissingProfile(
"微信手机号授权失败:缺少纯手机号".to_string(),
));
}
let country_code = phone_info.country_code.trim();
if country_code.is_empty() {
return Err(WechatProviderError::MissingProfile(
"微信手机号授权失败:缺少国家码".to_string(),
));
}
let phone_number = phone_info.phone_number.trim();
if phone_number.is_empty() {
return Err(WechatProviderError::MissingProfile(
"微信手机号授权失败:缺少完整手机号".to_string(),
));
}
Ok(WechatPhoneNumberProfile {
phone_number: phone_number.to_string(),
pure_phone_number: Some(pure_phone_number.to_string()),
country_code: Some(country_code.to_string()),
})
}
#[derive(Debug, Deserialize)]
@@ -1118,20 +1146,7 @@ impl RealWechatProvider {
let phone_info = payload.phone_info.ok_or_else(|| {
WechatProviderError::MissingProfile("微信手机号授权失败:缺少手机号信息".to_string())
})?;
let phone_number = phone_info
.pure_phone_number
.clone()
.or(phone_info.phone_number.clone())
.filter(|value| !value.trim().is_empty())
.ok_or_else(|| {
WechatProviderError::MissingProfile("微信手机号授权失败:缺少手机号".to_string())
})?;
Ok(WechatPhoneNumberProfile {
phone_number,
pure_phone_number: phone_info.pure_phone_number,
country_code: phone_info.country_code,
})
normalize_wechat_phone_number_info(phone_info)
}
async fn request_mini_program_access_token(
@@ -2074,7 +2089,7 @@ mod tests {
"errcode": 0,
"errmsg": "ok",
"phone_info": {
"phoneNumber": "+8613800138000",
"phoneNumber": "13800138000",
"purePhoneNumber": "13800138000",
"countryCode": "86"
}
@@ -2083,9 +2098,55 @@ mod tests {
.expect("wechat phone number response should parse");
let phone_info = payload.phone_info.expect("phone info should exist");
assert_eq!(phone_info.phone_number.as_deref(), Some("+8613800138000"));
assert_eq!(phone_info.pure_phone_number.as_deref(), Some("13800138000"));
assert_eq!(phone_info.country_code.as_deref(), Some("86"));
assert_eq!(phone_info.phone_number, "13800138000");
assert_eq!(phone_info.pure_phone_number, "13800138000");
assert_eq!(phone_info.country_code, "86");
let profile = normalize_wechat_phone_number_info(phone_info)
.expect("wechat phone profile should normalize");
assert_eq!(profile.phone_number, "13800138000");
assert_eq!(profile.pure_phone_number.as_deref(), Some("13800138000"));
assert_eq!(profile.country_code.as_deref(), Some("86"));
}
#[test]
fn wechat_phone_number_success_response_requires_country_code() {
let error = serde_json::from_str::<WechatPhoneNumberResponse>(
r#"{
"errcode": 0,
"phone_info": {
"phoneNumber": "+8613800138000",
"purePhoneNumber": "13800138000"
}
}"#,
)
.expect_err("missing provider country code should fail deserialization");
assert!(error.to_string().contains("countryCode"));
}
#[test]
fn wechat_phone_number_error_response_may_omit_phone_info() {
let payload = serde_json::from_str::<WechatPhoneNumberResponse>(
r#"{
"errcode": 40029,
"errmsg": "invalid code"
}"#,
)
.expect("wechat error response should remain parseable");
assert!(payload.phone_info.is_none());
}
#[test]
fn wechat_phone_number_profile_requires_non_empty_phone_number() {
let error = normalize_wechat_phone_number_info(WechatPhoneNumberInfo {
phone_number: " ".to_string(),
pure_phone_number: "13800138000".to_string(),
country_code: "86".to_string(),
})
.expect_err("empty provider phone number should fail closed");
assert!(matches!(error, WechatProviderError::MissingProfile(_)));
}
#[test]