收紧微信手机号响应非空契约
按微信官方响应文档将 phoneNumber、purePhoneNumber、countryCode 设为必填字段 补充字段缺失、错误响应和空字符串的失败关闭测试
This commit is contained in:
@@ -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]
|
||||
|
||||
Reference in New Issue
Block a user