如何解决Nuxt VueFire中Session Cookie与App Check及密钥限制的兼容问题?
问题背景
尝试在Nuxt项目中结合VueFire实现Session Cookie认证,核心配置如下:
// nuxt.config.ts export default defineNuxtConfig({ runtimeConfig: { public: { brandName: "", fbApiKey: "", fbAuthDomain: "", projectId: "", fbDefaultStorageBucket: "", fbMessagingSenderId: "", fbAppId: "", fbMeasurementId: "", gcpRecaptchaEnterpriseSiteKey: "", }, }, vuefire: { config: { apiKey: process.env.NUXT_PUBLIC_FB_API_KEY, authDomain: process.env.NUXT_PUBLIC_FB_AUTH_DOMAIN, projectId: process.env.NUXT_PUBLIC_PROJECT_ID, storageBucket: process.env.NUXT_PUBLIC_FB_DEFAULT_STORAGE_BUCKET, messagingSenderId: process.env.NUXT_PUBLIC_FB_MESSAGING_SENDER_ID, appId: process.env.NUXT_PUBLIC_FB_APP_ID, measurementId: process.env.NUXT_PUBLIC_FB_MEASUREMENT_ID, }, auth: { enabled: true, sessionCookie: true, }, appCheck: { debug: process.env.NODE_ENV !== "production", isTokenAutoRefreshEnabled: true, provider: "ReCaptchaEnterprise", key: process.env.NUXT_PUBLIC_GCP_RECAPTCHA_ENTERPRISE_SITE_KEY || "none", }, }, })
遇到两个核心错误:
- 同时启用App Check和Session Cookie时,服务器端触发:
500 Firebase: Error (auth/firebase-app-check-token-is-invalid.). at _fail (/Users/BenJackGill/Dev/seoturbo/node_modules/@firebase/auth/src/core/util/assert.ts:65:9) at _performFetchWithErrorHandling (/Users/BenJackGill/Dev/seoturbo/node_modules/@firebase/auth/src/api/index.ts:210:9) at process.processTicksAndRejections (node:internal/process/task_queues:95:5) at _performSignInRequest (/Users/BenJackGill/Dev/seoturbo/node_modules/@firebase/auth/src/api/index.ts:231:27) at Module.signInWithCustomToken (/Users/BenJackGill/Dev/seoturbo/node_modules/@firebase/auth/src/core/strategies/custom_token.ts:56:37) at async ./node_modules/nuxt-vuefire/dist/runtime/auth/plugin-authenticate-user.server.mjs:36:135
- Firebase浏览器API密钥设置域名限制后,服务器端触发:
500 Firebase: Error (auth/requests-from-referer-<empty>-are-blocked.). at _fail (/Users/BenJackGill/Dev/seoturbo/node_modules/@firebase/auth/src/core/util/assert.ts:65:9) at _performFetchWithErrorHandling (/Users/BenJackGill/Dev/seoturbo/node_modules/@firebase/auth/src/api/index.ts:210:9) at process.processTicksAndRejections (node:internal/process/task_queues:95:5) at _performSignInRequest (/Users/BenJackGill/Dev/seoturbo/node_modules/@firebase/auth/src/api/index.ts:231:27) at Module.signInWithCustomToken (/Users/BenJackGill/Dev/seoturbo/node_modules/@firebase/auth/src/core/strategies/custom_token.ts:56:37) at async ./node_modules/nuxt-vuefire/dist/runtime/auth/plugin-authenticate-user.server.mjs:36:135
同时,尝试跳过服务器端路由中间件无效,中间件代码如下:
// middleware/auth.ts export default defineNuxtRouteMiddleware(async (to, from) => { // 尝试跳过服务器端执行但无效 // if (import.meta.server) { // return; // } const user = await getCurrentUser(); if (!user) { return navigateTo({ path: "/login", }); } });
解决方案
1. 隔离App Check的客户端与服务器逻辑
App Check调试令牌仅在浏览器环境有效,服务器端需禁用App Check或使用Admin SDK验证:
// nuxt.config.ts vuefire: { // ...其他配置 appCheck: { // 仅在客户端启用App Check enabled: process.client, debug: process.env.NODE_ENV !== "production" && process.client, isTokenAutoRefreshEnabled: true, provider: "ReCaptchaEnterprise", key: process.env.NUXT_PUBLIC_GCP_RECAPTCHA_ENTERPRISE_SITE_KEY || "none", }, }
2. 解决API密钥域名限制
- 为服务器端单独创建无域名限制的Firebase API密钥,或在控制台将服务器IP加入允许列表;
- 配置Firebase Admin SDK用于服务器端Session Cookie验证:在
.env中添加服务账号信息:
FIREBASE_SERVICE_ACCOUNT='{"type": "service_account", "project_id": "...", ...}'
VueFire会自动使用Admin SDK处理服务器端认证,规避客户端API密钥的域名限制。
3. 修正路由中间件
确保中间件在服务器端正确放行,或使用VueFire提供的响应式用户状态:
// middleware/auth.ts export default defineNuxtRouteMiddleware(async (to, from) => { // 服务器端直接放行,依赖VueFire自动处理Session Cookie认证 if (import.meta.server) { return; } // 客户端验证用户状态 const user = await getCurrentUser(); if (!user) { return navigateTo("/login"); } });
若需服务器端验证,改用useCurrentUser()(自动处理服务器端 hydration):
// middleware/auth.ts export default defineNuxtRouteMiddleware(async (to, from) => { const user = useCurrentUser(); // 服务器端等待用户状态 hydration if (import.meta.server && !user.value) { return navigateTo("/login"); } // 客户端验证 if (import.meta.client && !await getCurrentUser()) { return navigateTo("/login"); } });
内容的提问来源于stack exchange,提问作者TinyTiger
相关产品推荐
相关产品推荐

