AGC 认证续期失败不再降级成字符串

- refresh_session_inner 的非权威失败直接返回 Err(ClientAuthError),不再折成 error_message 字符串
- ClientAuthStateView 删除 error_message 字段,状态收窄为 authenticated / unauthenticated
- ClientAuthRefreshView 删除 error_message 与 failed 状态,authoritative 只在未登录时为 true
- read_client_auth_state 把续期失败原样透传给命令出口,不再投影出 unavailable 第三态
This commit is contained in:
2026-10-01 20:35:47 +08:00
parent 478b9c9891
commit 0798bf5219
@@ -49,14 +49,12 @@ const AUTH_AUTHORITY_MESSAGE: &str = "登录状态已失效,请重新登录";
#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
#[serde(rename_all = "camelCase")]
pub(crate) struct ClientAuthStateView {
/// `authenticated` / `unauthenticated` / `unavailable`。
/// `authenticated` / `unauthenticated`。
pub(crate) status: String,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub(crate) user: Option<AuthUserPayload>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub(crate) api_base_url: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub(crate) error_message: Option<String>,
}
#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
@@ -66,18 +64,17 @@ pub(crate) struct ClientLoginCodeView {
pub(crate) expires_in_seconds: u64,
}
/// 续期结果。`stale` 表示续期期间身份已经变化,调用方不得重放旧身份请求。
/// 续期结果。`stale` 表示续期期间身份已经变化,调用方不得重放旧身份请求;
/// 非权威失败(网络 / 5xx / 契约异常)不在这里降级成字符串,直接以 `Err(ClientAuthError)` 返回。
#[derive(Clone, Debug, PartialEq, Serialize)]
#[serde(rename_all = "camelCase")]
pub(crate) struct ClientAuthRefreshView {
/// `refreshed` / `unauthenticated` / `stale` / `failed`。
/// `refreshed` / `unauthenticated` / `stale`。
pub(crate) status: String,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub(crate) user: Option<AuthUserPayload>,
#[serde(default)]
pub(crate) authoritative: bool,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub(crate) error_message: Option<String>,
}
#[derive(Clone, Debug, Default, Deserialize, PartialEq, Serialize)]
@@ -808,7 +805,6 @@ fn auth_state_view(
status: status.to_string(),
user,
api_base_url,
error_message: None,
}
}
@@ -886,7 +882,6 @@ async fn refresh_session_inner(
status: "unauthenticated".to_string(),
user: None,
authoritative: true,
error_message: None,
});
};
let _guard = refresh_lock().lock().await;
@@ -902,7 +897,6 @@ async fn refresh_session_inner(
status: "refreshed".to_string(),
user: Some(user),
authoritative: false,
error_message: None,
});
}
}
@@ -934,15 +928,11 @@ async fn refresh_session_inner(
status: "unauthenticated".to_string(),
user: None,
authoritative: true,
error_message: None,
});
}
return Ok(ClientAuthRefreshView {
status: "failed".to_string(),
user: None,
authoritative: false,
error_message: Some(error.message().to_string()),
});
// 非权威失败不再降级成字符串:把 typed error 原样交给命令出口,
// 由前端 `invokeClientAuth` 转成 `ClientAuthFailure` 并按变体分流。
return Err(error);
}
};
let token: TokenResponse = serde_json::from_value(refreshed.data).map_err(|_| {
@@ -977,7 +967,6 @@ async fn refresh_session_inner(
status: "stale".to_string(),
user: None,
authoritative: false,
error_message: None,
});
}
let view = auth_state_view(
@@ -990,7 +979,6 @@ async fn refresh_session_inner(
status: "refreshed".to_string(),
user: Some(user),
authoritative: false,
error_message: None,
})
}
Ok(None) => {
@@ -1001,7 +989,6 @@ async fn refresh_session_inner(
status: "unauthenticated".to_string(),
user: None,
authoritative: true,
error_message: None,
})
}
Err(error) if error.is_authority_failure() => {
@@ -1012,15 +999,9 @@ async fn refresh_session_inner(
status: "unauthenticated".to_string(),
user: None,
authoritative: true,
error_message: None,
})
}
Err(error) => Ok(ClientAuthRefreshView {
status: "failed".to_string(),
user: None,
authoritative: false,
error_message: Some(error.message().to_string()),
}),
Err(error) => Err(error),
}
}
@@ -1063,20 +1044,10 @@ pub(crate) async fn read_client_auth_state(
refresh.user,
Some(session.api_base_url),
)),
"stale" | "unauthenticated" => Ok(auth_state_view("unauthenticated", None, None)),
_ => Ok(ClientAuthStateView {
status: "unavailable".to_string(),
user: None,
api_base_url: Some(session.api_base_url),
error_message: refresh.error_message,
}),
// `stale`(续期期间身份已变化)与 `unauthenticated` 都按未登录处理。
_ => Ok(auth_state_view("unauthenticated", None, None)),
},
Err(error) => Ok(ClientAuthStateView {
status: "unavailable".to_string(),
user: None,
api_base_url: Some(session.api_base_url),
error_message: Some(error.message().to_string()),
}),
Err(error) => Err(error),
}
}
@@ -1493,7 +1464,6 @@ mod tests {
wechat_account: None,
}),
api_base_url: Some(DEVELOPMENT_ORIGIN.to_string()),
error_message: None,
};
let serialized = serde_json::to_string(&view).expect("serialize auth state");
for forbidden in [