如何基于React实现Manifest V3 Chrome扩展Firebase谷歌账号认证?
分步实现Manifest V3 Chrome扩展 + Firebase登录(内嵌iframe方案)
1. 配置Manifest V3文件
调整manifest.json,确保CSP、权限和页面配置符合Manifest V3规则:
- 新增必要权限:
identity(用于身份验证)、storage(存储用户状态) - 配置CSP:允许Firebase资源加载及谷歌登录iframe的访问
- 注册登录页面并暴露为可访问资源
示例manifest.json核心片段:
{ "manifest_version": 3, "name": "你的扩展名称", "version": "1.0", "permissions": ["identity", "storage"], "action": { "default_popup": "index.html" // React打包后的主弹窗页面 }, "content_security_policy": { "extension_pages": "script-src 'self'; object-src 'none'; frame-src https://accounts.google.com/;", "sandbox": "sandbox allow-scripts allow-top-navigation; script-src 'self' https://www.gstatic.com/firebasejs/9.23.0/firebase-app.js https://www.gstatic.com/firebasejs/9.23.0/firebase-auth.js;" }, "web_accessible_resources": [ { "resources": ["login.html"], "matches": ["<all_urls>"] } ] }
2. 安装并初始化Firebase(React项目)
- 通过npm安装Firebase模块化SDK:
npm install firebase
- 创建
firebase.config.js初始化Firebase实例:
import { initializeApp } from "firebase/app"; import { getAuth } from "firebase/auth"; import { getFirestore } from "firebase/firestore"; const firebaseConfig = { apiKey: "YOUR_API_KEY", authDomain: "YOUR_AUTH_DOMAIN", projectId: "YOUR_PROJECT_ID", storageBucket: "YOUR_STORAGE_BUCKET", messagingSenderId: "YOUR_SENDER_ID", appId: "YOUR_APP_ID" }; const app = initializeApp(firebaseConfig); export const auth = getAuth(app); export const db = getFirestore(app);
3. 构建内嵌登录的React弹窗组件
在主弹窗组件(如Popup.js)中嵌入登录iframe,并监听来自iframe的登录结果:
import { useEffect, useState } from 'react'; import { auth } from './firebase.config'; import { signInWithCredential, GoogleAuthProvider } from 'firebase/auth'; function Popup() { const [user, setUser] = useState(null); useEffect(() => { const handleMessage = (event) => { // 验证消息来源为扩展内部 if (event.origin !== chrome.runtime.getURL('')) return; if (event.data.type === 'LOGIN_SUCCESS') { const credential = GoogleAuthProvider.credential(event.data.idToken); signInWithCredential(auth, credential) .then(userCredential => setUser(userCredential.user)) .catch(err => console.error('凭证验证失败:', err)); } }; window.addEventListener('message', handleMessage); return () => window.removeEventListener('message', handleMessage); }, []); if (user) { return <div>已登录:{user.email}</div>; } return ( <div style={{ width: '300px', padding: '20px' }}> <h3>登录你的账号</h3> <iframe src={chrome.runtime.getURL('login.html')} style={{ width: '100%', height: '400px', border: 'none' }} title="Firebase Login" ></iframe> </div> ); } export default Popup;
4. 编写独立登录页面(login.html)
在React项目public目录下创建login.html,实现谷歌登录逻辑并通过postMessage传递结果:
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>登录</title> <script src="https://www.gstatic.com/firebasejs/9.23.0/firebase-app.js"></script> <script src="https://www.gstatic.com/firebasejs/9.23.0/firebase-auth.js"></script> </head> <body> <div id="loginBtn"></div> <script> const firebaseConfig = { // 与React项目中一致的Firebase配置 apiKey: "YOUR_API_KEY", authDomain: "YOUR_AUTH_DOMAIN", projectId: "YOUR_PROJECT_ID", storageBucket: "YOUR_STORAGE_BUCKET", messagingSenderId: "YOUR_SENDER_ID", appId: "YOUR_APP_ID" }; const app = firebase.initializeApp(firebaseConfig); const auth = firebase.auth(); const provider = new firebase.auth.GoogleAuthProvider(); provider.setCustomParameters({ prompt: 'select_account' }); // 处理登录重定向结果 auth.getRedirectResult().then(result => { if (result.user) { result.user.getIdToken().then(idToken => { window.parent.postMessage( { type: 'LOGIN_SUCCESS', idToken }, chrome.runtime.getURL('') ); }); } }).catch(err => console.error('登录错误:', err)); // 渲染登录按钮 document.getElementById('loginBtn').innerHTML = '<button onclick="auth.signInWithRedirect(provider)">使用谷歌账号登录</button>'; </script> </body> </html>
5. 执行Firestore CRUD操作
登录成功后,即可通过初始化的db对象操作Firestore:
import { collection, addDoc, getDocs } from "firebase/firestore"; import { db } from './firebase.config'; // 添加数据 const addUser = async (user) => { try { const docRef = await addDoc(collection(db, "users"), { email: user.email, name: user.displayName }); console.log("文档ID:", docRef.id); } catch (e) { console.error("添加失败:", e); } }; // 获取数据 const fetchUsers = async () => { const querySnapshot = await getDocs(collection(db, "users")); querySnapshot.forEach(doc => { console.log(`${doc.id} =>`, doc.data()); }); };
关键注意事项
- CSP配置必须严格:Manifest V3的
extension_pages不允许unsafe-inline/unsafe-eval,需指定具体Firebase CDN版本,避免通配符 - 消息来源验证:使用
postMessage时必须校验event.origin,防止恶意消息注入 - Firebase控制台配置:需在“授权域”中添加扩展ID(格式:
chrome-extension://<你的扩展ID>)
内容的提问来源于stack exchange,提问作者Slava709
相关产品推荐
相关产品推荐

