與源碼解析)
開發(fā)工具后端【免費下載鏈接】firebase-js-sdkFirebase Javascript SDK項目地址https://gitcode.com/gh_mirrors/fi/firebase-js-sdk點擊查看免費下載RecaptchaVerifier是 Firebase JS SDKfirebase-js-sdk中基于 Google reCAPTCHA 的應用驗證器實現(xiàn)是手機號登錄、手機號注冊等需要人機校驗場景的核心組件。本文以 API 參考文檔 auth.recaptchaverifier.md 為主體結(jié)合packages/auth包源碼完整講解它的構(gòu)造函數(shù)參數(shù)、三個核心方法render/verify/clear的用法、與signInWithPhoneNumber的配合方式以及底層運行原理幫助你在實際項目中正確接入并避開常見陷阱。概述RecaptchaVerifier 是什么RecaptchaVerifier是一個基于 reCAPTCHA 的應用驗證器Application Verifier它實現(xiàn)了 Firebase Auth 內(nèi)部定義的ApplicationVerifierInternal接口export declare class RecaptchaVerifier implements ApplicationVerifierInternal在 Firebase Auth 中凡是需要證明操作來自真實用戶的敏感操作典型的如手機號登錄/注冊都必須傳入一個實現(xiàn)ApplicationVerifier接口的對象。從源碼可見ApplicationVerifier接口只要求兩個成員packages/auth/src/model/public_types.tstype驗證器類型標識用于區(qū)分驗證方式verify()執(zhí)行驗證過程并返回一個可用于證明請求有效性的 token。注釋中明確指出目前RecaptchaVerifier是該接口的唯一實現(xiàn)。因此它是 Firebase Auth 手機號驗證流程中不可繞過的關鍵組件。需要特別強調(diào)的是文檔中的一條重要限制RecaptchaVerifierdoes not work in a Node.js environment.即RecaptchaVerifier不能在 Node.js 環(huán)境下工作它只面向瀏覽器Web環(huán)境。原因是它依賴document、window等瀏覽器全局對象以及動態(tài)加載外部腳本這一點在源碼構(gòu)造函數(shù)與init()方法中都有明確校驗見下文運行限制一節(jié)。構(gòu)造函數(shù)三個參數(shù)的完整語義constructor(authExtern: Auth, containerOrId: HTMLElement | string, parameters?: RecaptchaParameters);參數(shù)一authExternAuth 實例對應你的 Firebase Auth 實例即getAuth()的返回值。它用于校驗、API 請求以及讀取languageCode驗證碼控件語言會跟隨 Auth 實例的語言設置。參數(shù)二containerOrId容器reCAPTCHA 掛載的容器可以是DOM 元素HTMLElement也可以是元素的 id 字符串。它的語義隨驗證碼的可見性不同而不同源碼構(gòu)造函數(shù)packages/auth/src/platform_browser/recaptcha/recaptcha_verifier.ts是這樣解析的const container typeof containerOrId string ? document.getElementById(containerOrId) : containerOrId; _assert(container, this.auth, AuthErrorCode.ARGUMENT_ERROR);三條關鍵規(guī)則若傳字符串它必須對應一個已存在于 DOM 中的元素 id初始化時元素必須已在頁面上若未找到會拋出argument-error對于可見的 reCAPTCHA非 invisible容器元素必須是空的。源碼validateStartingState()中明確斷言_assert( this.isInvisible || !this.container.hasChildNodes(), this.auth, AuthErrorCode.ARGUMENT_ERROR );如果容器里已有子節(jié)點會直接報錯因此在渲染可見驗證碼前要確保容器內(nèi)沒有任何內(nèi)容 3. 對于 invisible 驗證碼容器主要用于承載隱藏的 iframe規(guī)則相對寬松。參數(shù)三parameters可選 reCAPTCHA 參數(shù)可選的 reCAPTCHA 渲染參數(shù)類型為 RecaptchaParameters。該接口在源碼中是一個開放索引簽名packages/auth/src/model/public_types.ts即任意字符串鍵都可以傳入export interface RecaptchaParameters { [key: string]: any; }文檔明確說明除sitekey外的所有參數(shù)均被接受。sitekey由 Firebase Auth 后端為每個項目預先分配SDK 會在渲染時自動配置用戶不要也不能自行傳入——若在構(gòu)造時傳了sitekey源碼會在validateStartingState()中直接拋出參數(shù)錯誤recaptcha_verifier.ts。如果你不傳parametersSDK 會使用如下默認值源碼常量 recaptcha_verifier.tsconst DEFAULT_PARAMS: RecaptchaParameters { theme: light, type: image };常用參數(shù)均以 reCAPTCHA 官方文檔為準參數(shù)說明size設為invisible即啟用 invisible隱形reCAPTCHA不設置則為可見的復選框樣式theme主題light/dark默認lighttype挑戰(zhàn)類型image/audio默認imagecallbacktoken 生成后的回調(diào)可以是函數(shù)也可以是全局函數(shù)名字符串源碼makeTokenCallback兩種都支持expired-callbacktoken 過期時回調(diào)SDK 會忽略空 token 過期事件type 屬性驗證器類型標識readonly type recaptcha;type是只讀屬性固定值為recaptcha源碼常量RECAPTCHA_VERIFIER_TYPErecaptcha_verifier.ts。它用于讓 Firebase Auth 后端識別本次驗證使用的驗證器類型實現(xiàn)ApplicationVerifier接口的協(xié)議要求。render()渲染驗證碼控件render(): Promisenumber;在頁面上渲染 reCAPTCHA 控件返回一個resolve 為 reCAPTCHA widget ID 的 Promise。render()的源碼實現(xiàn)值得注意recaptcha_verifier.ts若實例已銷毀destroyed直接返回一個 rejected Promise若渲染正在進行renderPromise已存在返回同一個 Promise避免重復渲染首次調(diào)用時觸發(fā)內(nèi)部渲染流程失敗后會將renderPromise重置為null允許后續(xù)重試。底層渲染流程makeRenderPromise/initrecaptcha_verifier.ts大致為校驗當前環(huán)境必須為http/https且不是 Web Worker等待 DOM ready動態(tài)加載 reCAPTCHA v2 腳本加載細節(jié)見下文底層原理調(diào)用后端接口getRecaptchaParams獲取項目對應的siteKey若是可見驗證碼SDK 會在容器內(nèi)再創(chuàng)建一個空的div作為真正的渲染掛載點guaranteedEmpty確??丶秩静粫苋萜髟瓋?nèi)容影響調(diào)用grecaptcha.render(container, parameters)得到 widget ID。verify()等待用戶完成驗證并獲取 tokenverify(): Promisestring;等待用戶完成 reCAPTCHA 挑戰(zhàn)并 resolve 出 reCAPTCHA token一個字符串。這是ApplicationVerifier接口的核心契約也是傳給 Firebase 后端證明操作來自真實用戶的憑據(jù)。源碼實現(xiàn)recaptcha_verifier.ts的邏輯很精巧async verify(): Promisestring { this.assertNotDestroyed(); const id await this.render(); const recaptcha this.getAssertedRecaptcha(); const response recaptcha.getResponse(id); if (response) { return response; // 已有 token直接返回 } return new Promisestring(resolve { const tokenChange (token: string): void { if (!token) { return; // 忽略 token 過期事件空 token } this.tokenChangeListeners.delete(tokenChange); resolve(token); }; this.tokenChangeListeners.add(tokenChange); if (this.isInvisible) { recaptcha.execute(id); // invisible 模式需要主動觸發(fā)執(zhí)行 } }); }要點如果用戶此前已經(jīng)完成過驗證getResponse有值verify()直接復用該 token不會再次彈出驗證碼否則它注冊一個內(nèi)部 token 監(jiān)聽器等待驗證完成空 token過期事件會被忽略繼續(xù)等待下一次成功驗證invisible 模式下會自動調(diào)用grecaptcha.execute(id)主動觸發(fā)隱形驗證無需用戶點擊可見模式下則等待用戶勾選/完成挑戰(zhàn)后由回調(diào)驅(qū)動 resolve。clear()清理控件并銷毀實例clear(): void;清除頁面上的 reCAPTCHA 控件并銷毀當前實例。源碼實現(xiàn)recaptcha_verifier.tsclear(): void { this.assertNotDestroyed(); this.destroyed true; this._recaptchaLoader.clearedOneInstance(); if (!this.isInvisible) { this.container.childNodes.forEach(node { this.container.removeChild(node); }); } }將實例標記為destroyed此后調(diào)用render/verify/clear都會拋出internal-error通知 loader 釋放一個實例計數(shù)對應ReCaptchaLoaderImpl的counter影響后續(xù)腳本復用策略對于可見驗證碼清空容器內(nèi)的所有子節(jié)點即移除渲染出的控件invisible 模式由于控件承載在 iframe 中不做容器清空。實戰(zhàn)與手機號登錄signInWithPhoneNumber配合RecaptchaVerifier最典型的應用場景是手機號登錄。官方類型注釋給出了完整示例packages/auth/src/model/public_types.tsconst recaptchaVerifier new RecaptchaVerifier( auth, recaptcha-container, // 容器 id或直接傳 DOM 元素 { size: invisible // 可選使用隱形驗證碼 } ); // 觸發(fā)手機號驗證碼發(fā)送RecaptchaVerifier 會自動完成人機驗證 const confirmationResult await signInWithPhoneNumber( auth, phoneNumber, recaptchaVerifier ); // 用戶輸入短信驗證碼后確認登錄 const userCredential await confirmationResult.confirm(verificationCode);完整落地步驟在頁面 HTML 中放置容器可見模式必須為空div idrecaptcha-container/div創(chuàng)建驗證器并渲染import { getAuth, RecaptchaVerifier, signInWithPhoneNumber } from firebase/auth; const auth getAuth(); const appVerifier new RecaptchaVerifier(auth, recaptcha-container); await appVerifier.render(); // 立即渲染控件也可省略verify 時自動渲染調(diào)用signInWithPhoneNumberSDK 內(nèi)部會自動調(diào)用verify()拿到 token 并隨請求發(fā)送給后端確認驗證碼confirmationResult.confirm(code)完成登錄、綁定或重新認證。集成測試可以佐證這一調(diào)用關系packages/auth/test/integration/flows/phone.test.ts中正是先new RecaptchaVerifier(auth, fakeRecaptchaContainer)再將其傳入signInWithPhoneNumberphone.test.ts。使用完例如單頁應用切換頁面時應調(diào)用appVerifier.clear()釋放資源避免驗證碼控件殘留。底層原理reCAPTCHA 腳本加載與 siteKey 獲取腳本動態(tài)加載與超時控制RecaptchaVerifier并不會要求你在頁面手動引入 reCAPTCHA 腳本而是通過ReCaptchaLoaderImpl動態(tài)加載packages/auth/src/platform_browser/recaptcha/recaptcha_loader.ts加載地址為 reCAPTCHA v2 腳本并附加onload回調(diào)名、render: explicit顯式渲染模式以及hl語言參數(shù)取自auth.languageCode網(wǎng)絡超時窗口為30~60 秒new Delay(30000, 60000)超時拋network-request-failed若window.grecaptcha.render已存在比如 App Check 等其他模塊已加載過 reCAPTCHA會盡量復用而不重復加載避免破壞頁面上已渲染的驗證碼。siteKey 由后端下發(fā)你無需也不能提供 siteKey。在init()中 SDK 會調(diào)用認證 API 的GET_RECAPTCHA_PARAM端點獲取本項目預分配的recaptchaSiteKeypackages/auth/src/api/authentication/recaptcha.tsexport async function getRecaptchaParams(auth: Auth): Promisestring { return ( ( await _performApiRequestvoid, GetRecaptchaParamResponse( auth, HttpMethod.GET, Endpoint.GET_RECAPTCHA_PARAM ) ).recaptchaSiteKey || ); }拿到 siteKey 后才寫入this.parameters.sitekey并完成渲染這就是Firebase Auth 后端為每個項目配置 reCAPTCHA的具體實現(xiàn)。測試模式Mock reCAPTCHA在集成測試或使用 Auth 模擬器Emulator時不需要真實加載 Google 驗證碼服務。SDK 提供了開關auth.settings.appVerificationDisabledForTesting開啟該開關后構(gòu)造函數(shù)會選用MockReCaptchaLoaderImplrecaptcha_verifier.ts直接返回一個本地MockReCaptcha不會發(fā)起任何網(wǎng)絡請求在連接 Auth 模擬器時該開關會被自動置為truepackages/auth/src/core/auth/emulator.ts這就是為什么使用useEmulator后無需處理真實驗證碼也能跑通手機號登錄流程。運行限制與常見錯誤排查限制/場景說明Node.js 環(huán)境不適用。構(gòu)造時斷言typeof document ! undefined無 DOM 直接拋operation-not-supported非 http/https 頁面init()中斷言_isHttpOrHttps()本地file://等協(xié)議無法工作Web Worker顯式排除init()會拋internal-error傳入sitekey參數(shù)構(gòu)造時拋argument-errorsitekey 由后端下發(fā)可見模式容器非空構(gòu)造時拋argument-error容器必須為空容器 id 不存在構(gòu)造時拋argument-error銷毀后繼續(xù)使用render/verify/clear拋internal-error網(wǎng)絡超時腳本加載 30~60 秒超時后拋network-request-failed小結(jié)RecaptchaVerifier是 Firebase Auth 在 Web 端進行人機驗證的唯一內(nèi)置實現(xiàn)構(gòu)造時傳入 Auth 實例、容器與可選參數(shù)verify()負責產(chǎn)出驗證 tokenrender()控制控件渲染時機clear()負責清理配合signInWithPhoneNumber即可完成手機號登錄/注冊的安全校驗。理解其sitekey 由后端下發(fā)、腳本動態(tài)加載、測試模式走 Mock這三條實現(xiàn)主線能幫你在真實項目中更快定位與解決問題。相關源碼可繼續(xù)查閱 recaptcha_verifier.ts、recaptcha_loader.ts 與集成測試 phone.test.ts。贊分享開發(fā)工具后端【免費下載鏈接】firebase-js-sdkFirebase Javascript SDK項目地址https://gitcode.com/gh_mirrors/fi/firebase-js-sdk點擊查看免費下載相關推薦Firebase JS SDK 深度解析PhoneAuthCredential 手機號驗證碼憑證的機制與實戰(zhàn)Firebase JS SDK 深度解析PhoneAuthCredential 手機號驗證碼憑證的機制與實戰(zhàn) 導讀 PhoneAuthCredential 是開發(fā)工具后端Firebase JS SDK 核心工具包 firebase/util 完全指南公開 API、源碼實現(xiàn)與實戰(zhàn)用法Firebase JS SDK 核心工具包 firebase/util 完全指南公開 API、源碼實現(xiàn)與實戰(zhàn)用法 導讀 firebase/util 是 F開發(fā)工具后端Firebase JS SDK 的 ApplicationVerifier 接口從接口契約到 reCAPTCHA 實戰(zhàn)Firebase JS SDK 的 ApplicationVerifier 接口從接口契約到 reCAPTCHA 實戰(zhàn) ApplicationVerifier開發(fā)工具后端上一篇5分鐘精通biliTickerBuyB站會員購搶票開源工具終極指南下一篇前端路由性能優(yōu)化history庫高級應用技巧創(chuàng)作聲明:本文部分內(nèi)容由AI輔助生成(AIGC),僅供參考