Vue.js集成Firebase手机号登录报错:TypeError: verifier.verify is not a function
Firebase Phone Auth 报错:TypeError: verifier.verify is not a function 解决方法
问题场景
首次在Vue.js中集成Firebase的signInWithPhoneNumber功能,reCAPTCHA能正常加载验证,但调用signInWithPhoneNumber时触发以下错误:
TypeError: verifier.verify is not a function at _verifyPhoneNumber (phone.ts?47a7:178:1) at signInWithPhoneNumber (phone.ts?47a7:106:1) at VueComponent.signIn (SignUp.vue?611a:68:1) at callback (SignUp.vue?611a:50:1) at eval (recaptcha_verifier.ts?c937:220:1) at lW.Y.lW.o (recaptcha__en.js:788:178) at M.R (recaptcha__en.js:437:30) at new Promise (<anonymous>) at lk.C (recaptcha__en.js:437:2) at Array.<anonymous> (recaptcha__en.js:415:375)
用户提供的代码如下:
模板代码
<template> <div> <h2>SignUp</h2> +60<input type="number" v-model="phNo" placeholder="Phone Number" /> <button id="sign-in-button" @click="sendOtp">Get Recaptcha</button> <div id="recaptcha-container"></div> <br /> <input type="number" v-model="otp" placeholder="OTP" /> <button @click="verifyOtp">Verify</button><br /> <button @click="sendOtp()">Resend OTP</button> </div> </template>
脚本代码
<script> import { initializeApp } from "@firebase/app"; import firebaseConfig from "@/firebaseConfig"; import { getAuth, signInWithPhoneNumber, RecaptchaVerifier, } from "firebase/auth"; const app = initializeApp(firebaseConfig); const auth = getAuth(); export default { name: "SignUp", data() { return { phNo: "", appVerifier: "", otp: "", }; }, methods: { sendOtp() { window.recaptchaVerifier = new RecaptchaVerifier( "recaptcha-container", { size: "normal", callback: (response) => { // reCAPTCHA solved, allow signInWithPhoneNumber. this.appVerifier = response; this.signIn(response); }, "expired-callback": () => { // Response expired. Ask user to solve reCAPTCHA again. }, }, auth ); recaptchaVerifier.render().then((widgetId) => { window.recaptchaWidgetId = widgetId; }); }, signIn(something) { console.log("running"); let phoneNumber = "+60" + this.phNo; signInWithPhoneNumber(auth, phoneNumber, something) .then((confirmationResult) => { // SMS sent. Prompt user to type the code from the message, then sign the // user in with confirmationResult.confirm(code). window.confirmationResult = confirmationResult; this.verifyOtp(); }) .catch((error) => { // Error; SMS not sent // ... console.log(error); }); }, // verifyOtp() { // console.log("running"); let vm = this; let code = this.otp; window.confirmationResult .confirm(code) .then(function (result) { // User signed in successfully. var user = result.user; // ... //route to set password ! vm.$router.push({ path: "/setPassword" }); }) .catch(function (error) { // User couldn't sign in (bad verification code?) // ... }); }, }, created() {}, }; </script>
问题根源
核心错误是:signInWithPhoneNumber方法需要传入的是RecaptchaVerifier实例,但代码中错误地将reCAPTCHA回调返回的验证token传给了该方法,导致Firebase无法调用实例上的verify方法。
修复步骤
- 初始化RecaptchaVerifier时,将实例本身存入
this.appVerifier,而非回调的response - reCAPTCHA验证通过的回调中,直接调用
this.signIn(),无需传递response参数 - 修正
sendOtp中recaptchaVerifier.render()的引用(需加上window.前缀) - 移除
signIn方法的冗余参数,直接使用this.appVerifier作为signInWithPhoneNumber的第三个参数 - 移除
signIn中自动调用this.verifyOtp()的逻辑,OTP验证需等待用户输入后手动触发
修复后的完整脚本代码
<script> import { initializeApp } from "@firebase/app"; import firebaseConfig from "@/firebaseConfig"; import { getAuth, signInWithPhoneNumber, RecaptchaVerifier, } from "firebase/auth"; const app = initializeApp(firebaseConfig); const auth = getAuth(); export default { name: "SignUp", data() { return { phNo: "", appVerifier: null, otp: "", }; }, methods: { sendOtp() { // 初始化RecaptchaVerifier实例并保存 this.appVerifier = new RecaptchaVerifier( "recaptcha-container", { size: "normal", callback: () => { // reCAPTCHA验证通过后触发发送OTP this.signIn(); }, "expired-callback": () => { // 处理验证过期逻辑 alert("reCAPTCHA验证已过期,请重新验证"); }, }, auth ); // 渲染reCAPTCHA组件 this.appVerifier.render().then((widgetId) => { window.recaptchaWidgetId = widgetId; }); }, signIn() { if (!this.phNo) { alert("请输入手机号码"); return; } const phoneNumber = "+60" + this.phNo; // 使用保存的RecaptchaVerifier实例调用signInWithPhoneNumber signInWithPhoneNumber(auth, phoneNumber, this.appVerifier) .then((confirmationResult) => { // 保存确认结果,用于后续验证OTP window.confirmationResult = confirmationResult; alert("OTP已发送,请查收短信"); }) .catch((error) => { console.error("发送OTP失败:", error); // 重置reCAPTCHA if (window.recaptchaWidgetId) { this.appVerifier.reset(window.recaptchaWidgetId); } }); }, verifyOtp() { if (!this.otp || !window.confirmationResult) { alert("请先获取OTP并输入验证码"); return; } const code = this.otp; window.confirmationResult .confirm(code) .then((result) => { const user = result.user; console.log("用户登录成功:", user); this.$router.push({ path: "/setPassword" }); }) .catch((error) => { console.error("OTP验证失败:", error); alert("验证码错误或已过期,请重新输入"); }); }, }, }; </script>
模板说明
模板代码无需修改,保持原结构即可。
内容的提问来源于stack exchange,提问作者Abdullah Ibn Shahin
相关产品推荐
相关产品推荐

