feat: configure auth channel mismatch formats

This commit is contained in:
fawney19
2026-05-03 00:49:22 +08:00
parent 3a770306cc
commit e3ea2d1451
63 changed files with 585 additions and 39 deletions

View File

@@ -856,6 +856,10 @@ pub(super) fn build_admin_pool_key_payload(
"auth_type_by_format".to_string(),
json!(key.auth_type_by_format),
);
payload.insert(
"allow_auth_channel_mismatch_formats".to_string(),
json!(key.allow_auth_channel_mismatch_formats),
);
payload.insert(
"credential_kind".to_string(),
json!(auth_semantics.credential_kind().as_str()),

View File

@@ -14,6 +14,8 @@ pub(crate) struct AdminProviderKeyCreateRequest {
#[serde(default)]
pub(crate) auth_type_by_format: Option<serde_json::Value>,
#[serde(default)]
pub(crate) allow_auth_channel_mismatch_formats: Option<Option<Vec<String>>>,
#[serde(default)]
pub(crate) auth_config: Option<serde_json::Value>,
pub(crate) name: String,
#[serde(default)]
@@ -53,6 +55,8 @@ pub(crate) struct AdminProviderKeyUpdateRequest {
#[serde(default)]
pub(crate) auth_type_by_format: Option<serde_json::Value>,
#[serde(default)]
pub(crate) allow_auth_channel_mismatch_formats: Option<Vec<String>>,
#[serde(default)]
pub(crate) auth_config: Option<serde_json::Value>,
#[serde(default)]
pub(crate) name: Option<String>,

View File

@@ -1,7 +1,8 @@
use crate::handlers::admin::provider::shared::payloads::AdminProviderKeyCreateRequest;
use crate::handlers::admin::provider::write::normalize::{
normalize_api_format_json_object_keys, normalize_api_format_list, normalize_auth_type,
normalize_auth_type_by_format, validate_vertex_api_formats,
normalize_allow_auth_channel_mismatch_formats, normalize_api_format_json_object_keys,
normalize_api_format_list, normalize_auth_type, normalize_auth_type_by_format,
validate_vertex_api_formats,
};
use crate::handlers::admin::request::AdminAppState;
use crate::handlers::admin::shared::{
@@ -192,6 +193,14 @@ pub(crate) async fn build_admin_create_provider_key_record(
key.health_by_format = Some(json!({}));
key.circuit_breaker_by_format = Some(json!({}));
key.auth_type_by_format = auth_type_by_format;
let allow_auth_channel_mismatch_formats = payload
.allow_auth_channel_mismatch_formats
.unwrap_or_else(|| Some(api_formats.clone()));
key.allow_auth_channel_mismatch_formats = normalize_allow_auth_channel_mismatch_formats(
allow_auth_channel_mismatch_formats,
"allow_auth_channel_mismatch_formats",
&api_formats,
)?;
key.created_at_unix_ms = Some(now_unix_secs);
key.updated_at_unix_secs = Some(now_unix_secs);
Ok(key)

View File

@@ -1,7 +1,8 @@
use crate::handlers::admin::provider::shared::payloads::AdminProviderKeyUpdatePatch;
use crate::handlers::admin::provider::write::normalize::{
normalize_api_format_json_object_keys, normalize_api_format_list, normalize_auth_type,
normalize_auth_type_by_format, validate_vertex_api_formats,
normalize_allow_auth_channel_mismatch_formats, normalize_api_format_json_object_keys,
normalize_api_format_list, normalize_auth_type, normalize_auth_type_by_format,
validate_vertex_api_formats,
};
use crate::handlers::admin::request::AdminAppState;
use crate::handlers::admin::shared::{
@@ -221,6 +222,32 @@ pub(crate) async fn build_admin_update_provider_key_record(
} else {
updated.auth_type_by_format = None;
}
if fields.contains("allow_auth_channel_mismatch_formats") {
updated.allow_auth_channel_mismatch_formats =
normalize_allow_auth_channel_mismatch_formats(
payload.allow_auth_channel_mismatch_formats,
"allow_auth_channel_mismatch_formats",
&effective_api_formats,
)?;
} else if fields.contains("api_formats") {
let existing = updated
.allow_auth_channel_mismatch_formats
.as_ref()
.and_then(serde_json::Value::as_array)
.map(|items| {
items
.iter()
.filter_map(serde_json::Value::as_str)
.map(ToOwned::to_owned)
.collect::<Vec<_>>()
});
updated.allow_auth_channel_mismatch_formats =
normalize_allow_auth_channel_mismatch_formats(
existing,
"allow_auth_channel_mismatch_formats",
&effective_api_formats,
)?;
}
updated.auth_type = target_auth_type;

View File

@@ -81,6 +81,36 @@ pub(crate) fn normalize_auth_type_by_format(
}
}
pub(crate) fn normalize_allow_auth_channel_mismatch_formats(
values: Option<Vec<String>>,
field_name: &str,
api_formats: &[String],
) -> Result<Option<serde_json::Value>, String> {
let Some(values) = values else {
return Ok(None);
};
let allowed = api_formats.iter().cloned().collect::<BTreeSet<_>>();
let mut seen = BTreeSet::new();
let mut normalized = Vec::new();
for value in values {
let canonical = crate::ai_serving::normalize_api_format_alias(&value);
if canonical.is_empty() {
continue;
}
if !allowed.is_empty() && !allowed.contains(&canonical) {
return Err(format!("{field_name} 包含未选择的 API 格式: {canonical}"));
}
if seen.insert(canonical.clone()) {
normalized.push(serde_json::Value::String(canonical));
}
}
if normalized.is_empty() {
Ok(None)
} else {
Ok(Some(serde_json::Value::Array(normalized)))
}
}
pub(crate) fn normalize_auth_type(value: Option<&str>) -> Result<String, String> {
let auth_type = value.unwrap_or("api_key").trim().to_ascii_lowercase();
match auth_type.as_str() {

View File

@@ -120,6 +120,17 @@ pub(crate) async fn build_admin_system_export_providers_payload(
internal_priority: Some(key.internal_priority),
global_priority_by_format: key.global_priority_by_format.clone(),
auth_type_by_format: key.auth_type_by_format.clone(),
allow_auth_channel_mismatch_formats: key
.allow_auth_channel_mismatch_formats
.as_ref()
.and_then(serde_json::Value::as_array)
.map(|items| {
items
.iter()
.filter_map(serde_json::Value::as_str)
.map(ToOwned::to_owned)
.collect::<Vec<_>>()
}),
rpm_limit: key.rpm_limit,
allowed_models: key.allowed_models.as_ref().and_then(|value| {
value.as_array().map(|items| {

View File

@@ -1312,6 +1312,10 @@ pub(crate) fn build_admin_provider_key_response(
"auth_type_by_format".to_string(),
json!(key.auth_type_by_format),
);
payload.insert(
"allow_auth_channel_mismatch_formats".to_string(),
json!(key.allow_auth_channel_mismatch_formats),
);
payload.insert(
"credential_kind".to_string(),
json!(auth_semantics.credential_kind().as_str()),