conf 是爬蟲端與系統端(2FA Modal)之間的共用變數。auth_2fa_need、auth_2fa_options、auth_2fa_title、auth_2fa_msg 等),並讀取系統端回寫的結果。auth_2fa_method(使用者從選項中選擇)與 auth_2fa_code(使用者輸入的驗證碼)。
auth_2fa_method 與 auth_2fa_code 兩個使用者操作結果。
爬蟲端會將以下欄位寫入 conf 物件,系統端應依以下內容彈出 Modal:
| conf 欄位 | 型別 | 說明 | 必填 |
|---|---|---|---|
| conf.auth_2fa_need | boolean | 是否需要進行兩步驟驗證。true → 顯示彈窗;false / null → 不需要。 |
必填 |
| conf.auth_2fa_options | string[] |
可用的驗證方式列表,Modal 會依此動態產生按鈕。 可用值: "sms"(手機簡訊)、"app"(驗證器 App)、"email"(信箱)範例: ["sms", "app", "email"]、["sms"]
|
必填 |
| conf.auth_2fa_title | string | 銀行或服務名稱,顯示於 Modal 標題列。例如 "CUBE 網路銀行"、"台新 Richart"。 |
必填 |
| conf.auth_2fa_msg | string |
動態訊息,由爬蟲端寫入。用於顯示發送目的地等資訊。 例如: "已傳送簡訊驗證碼至 0907****48"、"已傳送驗證碼至 exam**@gmail.com"Modal 在每次狀態變化時會自動讀取並更新顯示。初始可為空字串。 |
選填 |
| conf.clientid_parentid | string | 客戶識別碼,格式如 #TW_065。 |
必填 |
// 爬蟲端初始化 conf 範例 const conf = { auth_2fa_need: true, auth_2fa_options: ["sms", "app", "email"], auth_2fa_title: "CUBE 網路銀行", auth_2fa_msg: "", // 初始為空,爬蟲端會動態更新 clientid_parentid: "#TW_065" }; if (conf.auth_2fa_need) { openModal(); // 觸發 2FA 彈窗 }
以下為爬蟲端與系統端(Modal)之間共用的全域變數:
| 變數名稱 | 型別 | 值 | 說明 |
|---|---|---|---|
| auth_2fa_need | boolean | true / false / null |
爬蟲端寫入。true:需要驗證(觸發 Modal)false / null:驗證已完成或不需要
|
| auth_2fa_options | string[] | ["sms","app","email"] |
爬蟲端寫入。設定可用驗證方式,Modal 據此渲染按鈕 |
| auth_2fa_title | string | 銀行名稱字串 | 爬蟲端寫入。顯示於 Modal 標題列的服務名稱 |
| auth_2fa_msg | string | 動態訊息字串 |
爬蟲端寫入,可隨時更新此變數來顯示訊息。 Modal 在狀態變化時自動讀取顯示。 常見用途:顯示發送目的地(如 "已傳送至 0907****48")
|
| 變數名稱 | 型別 | 值 | 說明 |
|---|---|---|---|
| auth_2fa_method | string | "sms" / "email" / "app" / "" |
系統端(Modal)寫入。使用者從 auth_2fa_options 中選擇的驗證方式。空字串代表尚未選擇 |
| auth_2fa_code | string | 6~10 位數字字串 | 系統端(Modal)寫入。使用者輸入的驗證碼,按下確定時寫入 |
auth_2fa_need = true、auth_2fa_options、auth_2fa_title、auth_2fa_msgauth_2fa_need == true,呼叫 openModal() 彈出驗證視窗
auth_2fa_options 顯示可用按鈕(簡訊 / 驗證器 App / Email)auth_2fa_method = "sms"(或 "email" / "app")
auth_2fa_method 變化後,負責發送驗證碼,並更新 auth_2fa_msgauth_2fa_msg = "已傳送簡訊驗證碼至 0907****48"auth_2fa_code = "xxxxxx"auth_2fa_code,進行驗證
auth_2fa_need = falseauth_2fa_method 與 auth_2fa_code(維持 auth_2fa_need = true)auth_2fa_need == true AND auth_2fa_method == "" AND auth_2fa_code == ""
爬蟲端透過輪詢或 Object.defineProperty 監聽系統端(Modal)回寫的 auth_2fa_method 與 auth_2fa_code:
// 方法 A:輪詢(簡單) const waitFor2FA = () => new Promise(resolve => { const timer = setInterval(() => { if (!auth_2fa_need) { clearInterval(timer); resolve(); } }, 500); }); // 等待驗證完成後繼續 await waitFor2FA(); console.log('驗證完成,繼續登入流程'); // 方法 B:property watch(進階) let _2fa_need = true; Object.defineProperty(window, 'auth_2fa_need', { get: () => _2fa_need, set: val => { _2fa_need = val; if (!val) onVerified(); // 驗證完成 callback } });
auth_2fa_method == "" 且 auth_2fa_need == true,
代表使用者尚未選擇驗證方式,爬蟲端應確保 Modal 保持開啟狀態。
// ── 爬蟲端初始化 conf ── const conf = { auth_2fa_need: true, auth_2fa_options: ["sms", "email"], auth_2fa_title: "國泰世華 CUBE", auth_2fa_msg: "", clientid_parentid: "#TW_065" }; // ── 系統端讀取 conf 並觸發 Modal ── auth_2fa_options = conf.auth_2fa_options; auth_2fa_title = conf.auth_2fa_title; openModal(); // ── 使用者在 Modal 選擇 sms ── // Modal 寫入 auth_2fa_method = "sms" // ── 爬蟲端偵測到 method 變化,發送驗證碼並更新訊息 ── auth_2fa_msg = "已傳送簡訊驗證碼至 0907****48"; // ── 使用者在 Modal 輸入驗證碼並按確定 ── // Modal 寫入 auth_2fa_code = "123456" // ── 爬蟲端讀取 auth_2fa_code 進行驗證 ── // 驗證成功: auth_2fa_need = false; // 驗證失敗:只需清空 method,維持 need=true → Modal 自動回到步驟 0 auth_2fa_method = ""; // auth_2fa_need 仍為 true
auth_2fa_method 與 auth_2fa_code。所有狀態透過 conf 變數傳遞。
以下示範系統端如何以 PHP 讀取 conf 設定、監聽 Modal 回寫的變數,並完成驗證碼核驗流程。
auth_2fa_method / auth_2fa_code 並以 AJAX 傳回 PHP 端驗證。
// init_2fa.php — 由系統端產生,嵌入頁面 <head> <?php // 從 session / 資料庫取得當前使用者的 2FA 設定 $options = get_user_2fa_methods($user_id); // e.g. ['sms','email'] $title = '國泰世華 CUBE'; $msg = ''; ?> <script> // 由 PHP 寫入 conf — Modal 會讀取這些值 var auth_2fa_need = true; var auth_2fa_options = <?= json_encode($options) ?>; var auth_2fa_title = <?= json_encode($title) ?>; var auth_2fa_msg = <?= json_encode($msg) ?>; var auth_2fa_method = ""; var auth_2fa_code = ""; </script>
// bridge.js(嵌入同一頁面) // 監聽 auth_2fa_method,偵測到選擇後呼叫 PHP 發送驗證碼 let _sentMethod = ""; setInterval(() => { if (auth_2fa_need && auth_2fa_method && auth_2fa_method !== _sentMethod) { _sentMethod = auth_2fa_method; fetch('/api/2fa/send.php', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ method: auth_2fa_method }) }) .then(r => r.json()) .then(res => { // PHP 回傳發送目的地,更新提示訊息 auth_2fa_msg = res.message; // e.g. "已傳送至 0907****48" }); } }, 300); // send.php — 發送驗證碼 <?php $data = json_decode(file_get_contents('php://input'), true); $method = $data['method'] ?? ''; switch ($method) { case 'sms': send_sms_otp($user_phone); $message = '已傳送簡訊至 ' . mask_phone($user_phone); break; case 'email': send_email_otp($user_email); $message = '已傳送 Email 至 ' . mask_email($user_email); break; case 'app': $message = '請開啟驗證器 App 取得驗證碼'; break; } header('Content-Type: application/json'); echo json_encode(['message' => $message]); ?>
// bridge.js(續) // 監聽 auth_2fa_code,偵測到後轉送至 PHP,再由爬蟲端決定成功或重試 // 系統端不判斷驗證成功或失敗 let _sending = false; setInterval(() => { if (auth_2fa_need && auth_2fa_code && !_sending) { _sending = true; const code = auth_2fa_code; const method = auth_2fa_method; auth_2fa_code = ""; // 立即清空,避免重複送出 _sending = false; fetch('/api/2fa/submit.php', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ method, code }) }); // 不處理回應 — 爬蟲端自行判斷結果 // 若爬蟲端認為需要重試,會清空 auth_2fa_method + auth_2fa_code // → Modal 自動偵測並重新彈出 } }, 300); // submit.php — 接收驗證碼並轉交爬蟲端,不回傳驗證結果 <?php $data = json_decode(file_get_contents('php://input'), true); $method = $data['method'] ?? ''; $code = $data['code'] ?? ''; // 將 method + code 寫入 session / queue,供爬蟲端取用 $_SESSION['2fa_submit'] = [ 'method' => $method, 'code' => $code, 'at' => time(), ]; header('Content-Type: application/json'); echo json_encode(['ok' => true]); ?>
// crawler_handler.php — 爬蟲端讀取 session 中的 code 後自行驗證 <?php $submit = $_SESSION['2fa_submit'] ?? null; if ($submit) { $valid = bank_verify_otp($submit['method'], $submit['code']); if ($valid) { // 驗證成功:通知前端關閉 Modal set_conf('auth_2fa_need', false); } else { // 驗證失敗:清空 method + code → Modal 自動重新彈出 // 條件:need==true AND method=="" AND code=="" → popup set_conf('auth_2fa_method', ''); set_conf('auth_2fa_code', ''); // auth_2fa_need 維持 true(不需要額外設定) } unset($_SESSION['2fa_submit']); } ?>
auth_2fa_method 與 auth_2fa_code,
Modal 偵測到三項條件(need=true + method="" + code="")即自動重新彈出。