From b77ea21ca8cbae971794387f307e8e2ad5d9a975 Mon Sep 17 00:00:00 2001 From: liumangmang Date: Tue, 2 Jun 2026 09:52:43 +0800 Subject: [PATCH] fix(frontend): support cookie_bundle candidate in AuthCaptureDialog and refreshAuth --- frontend/src/api/index.ts | 6 +++-- frontend/src/components/AuthCaptureDialog.vue | 25 ++++++++++++++----- frontend/src/views/PageViewer.vue | 4 +++ frontend/src/views/Upstreams.vue | 19 +++++++++++++- 4 files changed, 45 insertions(+), 9 deletions(-) diff --git a/frontend/src/api/index.ts b/frontend/src/api/index.ts index 2e46ae4..8701a82 100644 --- a/frontend/src/api/index.ts +++ b/frontend/src/api/index.ts @@ -427,7 +427,7 @@ export const customPagesApi = { create: (data: CustomPageForm) => api.post('/api/custom-pages', data), update: (id: number, data: Partial) => api.put(`/api/custom-pages/${id}`, data), delete: (id: number) => api.delete(`/api/custom-pages/${id}`), - refreshAuth: (id: number) => api.post<{ success: boolean; message: string }>(`/api/custom-pages/${id}/refresh-auth`), + refreshAuth: (id: number) => api.post<{ success: boolean; message: string; warning?: string }>(`/api/custom-pages/${id}/refresh-auth`), } // ——— Remote browser sessions ——— @@ -492,7 +492,7 @@ export interface AuthCaptureSession { } export interface AuthCaptureCandidate { - type: 'bearer_token' | 'cookie' | 'credential' | 'api_key' + type: 'bearer_token' | 'cookie' | 'cookie_bundle' | 'credential' | 'api_key' source: string preview: string label: string @@ -500,6 +500,8 @@ export interface AuthCaptureCandidate { value?: string cookie_name?: string cookie_value?: string + cookie_count?: number + cookie_names?: string[] new_api_user?: string } diff --git a/frontend/src/components/AuthCaptureDialog.vue b/frontend/src/components/AuthCaptureDialog.vue index dc7a342..15a5b66 100644 --- a/frontend/src/components/AuthCaptureDialog.vue +++ b/frontend/src/components/AuthCaptureDialog.vue @@ -169,9 +169,11 @@ function sameCandidate(a: AuthCaptureCandidate, b: AuthCaptureCandidate): boolea } function resolveCandidateValue(candidate: AuthCaptureCandidate): string { - return candidate.type === 'cookie' - ? (candidate.cookie_value || candidate.value || '') - : (candidate.value || '') + // cookie_bundle.value 已是完整 cookie 字符串;cookie.value 是 "name=value" 格式 + if (candidate.type === 'cookie') { + return candidate.cookie_value || candidate.value || '' + } + return candidate.value || '' } function resolveNewApiUser(rawResult: AuthCaptureResult, candidate: AuthCaptureCandidate): string | undefined { @@ -203,9 +205,13 @@ function resolveNewApiUser(rawResult: AuthCaptureResult, candidate: AuthCaptureC function defaultCandidateIndex(candidates: AuthCaptureCandidate[]): number { if (candidates.length === 0) return -1 - const sessionCookie = candidates.findIndex((candidate) => candidate.type === 'cookie' && candidate.cookie_name === 'session') + // 优先选完整 cookie bundle(包含 cf_clearance 等完整组合) + const bundle = candidates.findIndex((c) => c.type === 'cookie_bundle') + if (bundle >= 0) return bundle + // 其次选 session cookie + const sessionCookie = candidates.findIndex((c) => c.type === 'cookie' && c.cookie_name === 'session') if (sessionCookie >= 0) return sessionCookie - const anyCookie = candidates.findIndex((candidate) => candidate.type === 'cookie') + const anyCookie = candidates.findIndex((c) => c.type === 'cookie') if (anyCookie >= 0) return anyCookie return candidates.length === 1 ? 0 : -1 } @@ -504,7 +510,13 @@ onUnmounted(() => { // ——— Helpers ——— function badgeLabel(type: string): string { - return { bearer_token: 'Bearer', cookie: 'Cookie', api_key: 'API Key', credential: 'Key' }[type] || type + return { + bearer_token: 'Bearer', + cookie: 'Cookie', + cookie_bundle: '完整Cookie', + api_key: 'API Key', + credential: 'Key', + }[type] || type } function confClass(s: number): string { return s >= 80 ? 'conf-high' : s >= 50 ? 'conf-mid' : 'conf-low' @@ -571,6 +583,7 @@ function maskValue(v: string): string { } .candidate-badge.bearer_token { background: #e6f7ff; color: #1890ff; } .candidate-badge.cookie { background: #fff7e6; color: #d48806; } +.candidate-badge.cookie_bundle { background: #fff0d4; color: #b35c00; font-weight: 700; } .candidate-badge.api_key { background: #f0f5ff; color: #2f54eb; } .candidate-badge.credential { background: #f6ffed; color: #52c41a; } .candidate-label { font-size: 0.82rem; color: var(--el-text-color-secondary); } diff --git a/frontend/src/views/PageViewer.vue b/frontend/src/views/PageViewer.vue index d7ae463..06beff6 100644 --- a/frontend/src/views/PageViewer.vue +++ b/frontend/src/views/PageViewer.vue @@ -540,6 +540,10 @@ async function refreshAuth() { const res = await customPagesApi.refreshAuth(page.value.id) if (res.data.success) { ElMessage.success(res.data.message || '凭证已刷新') + // 宽松验证模式:凭证已写入但 API 调用失败时后端会返回 warning + if (res.data.warning) { + ElMessage.warning(res.data.warning) + } } else { ElMessage.warning(res.data.message || '刷新失败') } diff --git a/frontend/src/views/Upstreams.vue b/frontend/src/views/Upstreams.vue index 6869f39..533dd78 100644 --- a/frontend/src/views/Upstreams.vue +++ b/frontend/src/views/Upstreams.vue @@ -463,11 +463,28 @@ function openAuthCapture() { authCaptureVisible.value = true } -function handleAuthCaptureSelect(candidate: { type: string; value: string; cookie_name?: string; cookie_value?: string; new_api_user?: string }) { +function handleAuthCaptureSelect(candidate: { + type: string + value: string + cookie_name?: string + cookie_value?: string + cookie_count?: number + cookie_names?: string[] + new_api_user?: string +}) { if (candidate.type === 'bearer_token') { form.value.auth_type = 'bearer' form.value.auth_config.token = candidate.value ElMessage.success('已填入 Bearer Token') + } else if (candidate.type === 'cookie_bundle') { + // 完整 cookie 组:value 已是完整 "name1=v1; name2=v2" 字符串 + form.value.auth_type = 'cookie' + form.value.auth_config.cookie_string = candidate.value + if (candidate.new_api_user) { + form.value.auth_config.new_api_user = candidate.new_api_user + } + const countLabel = candidate.cookie_count ? `(${candidate.cookie_count} 个 cookie)` : '' + ElMessage.success(`已填入完整 Cookie 组${countLabel}`) } else if (candidate.type === 'cookie') { form.value.auth_type = 'cookie' form.value.auth_config.cookie_string = candidate.cookie_name && candidate.cookie_value