j) Create a signInWithPopup.js file in firebase-project/signInWithPopup.js

import { initializeApp } from \\'firebase/app\\';import { getAuth, signInWithPopup, GoogleAuthProvider } from \\'firebase/auth\\';const firebaseConfig = {  // Your web app\\'s Firebase configuration  // Replace with the config you copied from Firebase Console};const app = initializeApp(firebaseConfig);const auth = getAuth();// This gives you a reference to the parent frame, i.e. the offscreen document.const PARENT_FRAME = document.location.ancestorOrigins[0];const PROVIDER = new GoogleAuthProvider();function sendResponse(result) {  window.parent.postMessage(JSON.stringify(result), PARENT_FRAME);}window.addEventListener(\\'message\\', function({data}) {  if (data.initAuth) {    signInWithPopup(auth, PROVIDER)      .then(sendResponse)      .catch(sendResponse);  }});

k) Deploy the Firebase project

npm install -g firebase-toolsfirebase loginfirebase init hostingfirebase deploy

Note the hosting URL provided after deployment. You\\'ll need this for the Chrome extension.

Step 3: Set up the Chrome Extension

a) Navigate to the chrome-extension directory
cd ../chrome-extension

b) Create a manifest.json file in chrome-extension/manifest.json

{  \\\"manifest_version\\\": 3,  \\\"name\\\": \\\"Firebase Auth Extension\\\",  \\\"version\\\": \\\"1.0\\\",  \\\"description\\\": \\\"Chrome extension with Firebase Authentication\\\",  \\\"permissions\\\": [    \\\"identity\\\",    \\\"storage\\\",    \\\"offscreen\\\"  ],  \\\"host_permissions\\\": [    \\\"https://*.firebaseapp.com/*\\\"  ],  \\\"background\\\": {    \\\"service_worker\\\": \\\"background.js\\\",    \\\"type\\\": \\\"module\\\"  },  \\\"action\\\": {    \\\"default_popup\\\": \\\"popup.html\\\"  },  \\\"web_accessible_resources\\\": [    {      \\\"resources\\\": [\\\"offscreen.html\\\"],      \\\"matches\\\": [\\\"\\\"]    }  ],  \\\"oauth2\\\": {    \\\"client_id\\\": \\\"YOUR-ID.apps.googleusercontent.com\\\",    \\\"scopes\\\": [      \\\"openid\\\",       \\\"email\\\",       \\\"profile\\\"    ]  },  \\\"key\\\": \\\"-----BEGIN PUBLIC KEY-----\\\\nYOURPUBLICKEY\\\\n-----END PUBLIC KEY-----\\\"}

c) Create a popup.html file in chrome-extension/popup.html

    Firebase Auth Extension    

Firebase Auth Extension

d) Create a popup.js file in chrome-extension/popup.js

document.addEventListener(\\'DOMContentLoaded\\', function() {    const signInButton = document.getElementById(\\'signInButton\\');    const signOutButton = document.getElementById(\\'signOutButton\\');    const userInfo = document.getElementById(\\'userInfo\\');    function updateUI(user) {        if (user) {            userInfo.textContent = `Signed in as: ${user.email}`;            signInButton.style.display = \\'none\\';            signOutButton.style.display = \\'block\\';        } else {            userInfo.textContent = \\'Not signed in\\';            signInButton.style.display = \\'block\\';            signOutButton.style.display = \\'none\\';        }    }    chrome.storage.local.get([\\'user\\'], function(result) {        updateUI(result.user);    });    signInButton.addEventListener(\\'click\\', function() {        chrome.runtime.sendMessage({action: \\'signIn\\'}, function(response) {            if (response.user) {                updateUI(response.user);            }        });    });    signOutButton.addEventListener(\\'click\\', function() {        chrome.runtime.sendMessage({action: \\'signOut\\'}, function() {            updateUI(null);        });    });});

e) Create a background.js file in chrome-extension/background.js

const OFFSCREEN_DOCUMENT_PATH = \\'offscreen.html\\';const FIREBASE_HOSTING_URL = \\'https://your-project-id.web.app\\'; // Replace with your Firebase hosting URLlet creatingOffscreenDocument;async function hasOffscreenDocument() {    const matchedClients = await clients.matchAll();    return matchedClients.some((client) => client.url.endsWith(OFFSCREEN_DOCUMENT_PATH));}async function setupOffscreenDocument() {    if (await hasOffscreenDocument()) return;    if (creatingOffscreenDocument) {        await creatingOffscreenDocument;    } else {        creatingOffscreenDocument = chrome.offscreen.createDocument({            url: OFFSCREEN_DOCUMENT_PATH,            reasons: [chrome.offscreen.Reason.DOM_SCRAPING],            justification: \\'Firebase Authentication\\'        });        await creatingOffscreenDocument;        creatingOffscreenDocument = null;    }}async function getAuthFromOffscreen() {    await setupOffscreenDocument();    return new Promise((resolve, reject) => {        chrome.runtime.sendMessage({action: \\'getAuth\\', target: \\'offscreen\\'}, (response) => {            if (chrome.runtime.lastError) {                reject(chrome.runtime.lastError);            } else {                resolve(response);            }        });    });}chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {    if (message.action === \\'signIn\\') {        getAuthFromOffscreen()            .then(user => {                chrome.storage.local.set({user: user}, () => {                    sendResponse({user: user});                });            })            .catch(error => {                console.error(\\'Authentication error:\\', error);                sendResponse({error: error.message});            });        return true; // Indicates we will send a response asynchronously    } else if (message.action === \\'signOut\\') {        chrome.storage.local.remove(\\'user\\', () => {            sendResponse();        });        return true;    }});

f) Create an offscreen.html file in chrome-extension/offscreen.html

    Offscreen Document    

g) Create an offscreen.js file in _chrome-extension/offscreen.js
_

const FIREBASE_HOSTING_URL = \\'https://your-project-id.web.app\\'; // Replace with your Firebase hosting URLconst iframe = document.createElement(\\'iframe\\');iframe.src = FIREBASE_HOSTING_URL;document.body.appendChild(iframe);chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {    if (message.action === \\'getAuth\\' && message.target === \\'offscreen\\') {        function handleIframeMessage({data}) {            try {                const parsedData = JSON.parse(data);                window.removeEventListener(\\'message\\', handleIframeMessage);                sendResponse(parsedData.user);            } catch (e) {                console.error(\\'Error parsing iframe message:\\', e);            }        }        window.addEventListener(\\'message\\', handleIframeMessage);        iframe.contentWindow.postMessage({initAuth: true}, FIREBASE_HOSTING_URL);        return true; // Indicates we will send a response asynchronously    }});

Step 4: Configure Firebase Authentication

a) In the Firebase Console, go to Authentication > Sign-in method.
b) Enable Google as a sign-in provider.
c) Add your Chrome extension\\'s ID to the authorized domains list:
The format is: chrome-extension://YOUR_EXTENSION_ID
You can find your extension ID in Chrome\\'s extension management page after loading it as an unpacked extension.

Step 5: Load and Test the Extension

a) Open Google Chrome and go to chrome://extensions/.
b) Enable \\\"Developer mode\\\" in the top right corner.
c) Click \\\"Load unpacked\\\" and select your chrome-extension directory.
d) Click on the extension icon in Chrome\\'s toolbar to open the popup.
e) Click the \\\"Sign In\\\" button and test the authentication flow.

Troubleshooting

If you encounter CORS issues, ensure your Firebase hosting URL is correctly set in both background.js and offscreen.js.

Make sure your Chrome extension\\'s ID is correctly added to Firebase\\'s authorized domains.

Check the console logs in the popup, background script, and offscreen document for any error messages.

Conclusion

You now have a Chrome extension that uses Firebase Authentication with an offscreen document to handle the sign-in process. This setup allows for secure authentication without exposing sensitive Firebase configuration details directly in the extension code.

Remember to replace placeholder values (like YOUR_EXTENSION_ID, YOUR-CLIENT-ID, YOUR_PUBLIC_KEY, and your-project-id) with your actual values before publishing your extension.

","image":"http://www.luping.net/uploads/20241006/172820052667023f4e031a4.jpg","datePublished":"2024-11-02T15:11:01+08:00","dateModified":"2024-11-02T15:11:01+08:00","author":{"@type":"Person","name":"luping.net","url":"https://www.luping.net/articlelist/0_1.html"}}
”工欲善其事,必先利其器。“—孔子《论语.录灵公》
首页 > 编程 > 使用 Firebase 的 Chrome 扩展程序中的 Google 身份验证

使用 Firebase 的 Chrome 扩展程序中的 Google 身份验证

发布于2024-11-02
浏览:427

Google Authentication in a Chrome Extension with Firebase

We're writing this guide because the official guide by Google is missing a few important steps, we've linked in below:

Authenticate with Firebase in a Chrome extension

This will work on any operating system. For the purposes of this guide we'll be using Mac OS

Prerequisites

  • Google Chrome browser
  • A Google account
  • A Chrome web store developer account ($5 one time fee)
  • Node.js and npm installed

Step 1: Create the Project Structure

a) Create a new directory for your project:

mkdir firebase-chrome-auth
cd firebase-chrome-auth

b) Create two subdirectories:

mkdir chrome-extension
mkdir firebase-project

Step 2: Set up the Firebase Project

a) Go to the Firebase Console.
b) Click "Add project" and follow the steps to create a new project.
c) Once created, click on "Web" to add a web app to your project.
d) Register your app with a nickname (e.g., "Chrome Extension Auth").
e) Copy the Firebase configuration object. You'll need this later.

const firebaseConfig = {
  apiKey: "example",
  authDomain: "example.firebaseapp.com",
  projectId: "example",
  storageBucket: "example",
  messagingSenderId: "example",
  appId: "example"
};

f) Navigate to the firebase-project directory
cd firebase-project
g) Initialize a new npm project
npm init -y
h) Install Firebase:
npm install firebase
i) Create an index.html file in firebase-project/index.html


 
  Firebase Auth for Chrome Extension

Firebase Auth for Chrome Extension

j) Create a signInWithPopup.js file in firebase-project/signInWithPopup.js

import { initializeApp } from 'firebase/app';
import { getAuth, signInWithPopup, GoogleAuthProvider } from 'firebase/auth';

const firebaseConfig = {
  // Your web app's Firebase configuration
  // Replace with the config you copied from Firebase Console
};

const app = initializeApp(firebaseConfig);
const auth = getAuth();

// This gives you a reference to the parent frame, i.e. the offscreen document.
const PARENT_FRAME = document.location.ancestorOrigins[0];

const PROVIDER = new GoogleAuthProvider();

function sendResponse(result) {
  window.parent.postMessage(JSON.stringify(result), PARENT_FRAME);
}

window.addEventListener('message', function({data}) {
  if (data.initAuth) {
    signInWithPopup(auth, PROVIDER)
      .then(sendResponse)
      .catch(sendResponse);
  }
});

k) Deploy the Firebase project

npm install -g firebase-tools
firebase login
firebase init hosting
firebase deploy

Note the hosting URL provided after deployment. You'll need this for the Chrome extension.

Step 3: Set up the Chrome Extension

a) Navigate to the chrome-extension directory
cd ../chrome-extension

b) Create a manifest.json file in chrome-extension/manifest.json

{
  "manifest_version": 3,
  "name": "Firebase Auth Extension",
  "version": "1.0",
  "description": "Chrome extension with Firebase Authentication",
  "permissions": [
    "identity",
    "storage",
    "offscreen"
  ],
  "host_permissions": [
    "https://*.firebaseapp.com/*"
  ],
  "background": {
    "service_worker": "background.js",
    "type": "module"
  },
  "action": {
    "default_popup": "popup.html"
  },
  "web_accessible_resources": [
    {
      "resources": ["offscreen.html"],
      "matches": [""]
    }
  ],
  "oauth2": {
    "client_id": "YOUR-ID.apps.googleusercontent.com",
    "scopes": [
      "openid", 
      "email", 
      "profile"
    ]
  },
  "key": "-----BEGIN PUBLIC KEY-----\nYOURPUBLICKEY\n-----END PUBLIC KEY-----"
}

c) Create a popup.html file in chrome-extension/popup.html



    Firebase Auth Extension

Firebase Auth Extension

d) Create a popup.js file in chrome-extension/popup.js

document.addEventListener('DOMContentLoaded', function() {
    const signInButton = document.getElementById('signInButton');
    const signOutButton = document.getElementById('signOutButton');
    const userInfo = document.getElementById('userInfo');

    function updateUI(user) {
        if (user) {
            userInfo.textContent = `Signed in as: ${user.email}`;
            signInButton.style.display = 'none';
            signOutButton.style.display = 'block';
        } else {
            userInfo.textContent = 'Not signed in';
            signInButton.style.display = 'block';
            signOutButton.style.display = 'none';
        }
    }

    chrome.storage.local.get(['user'], function(result) {
        updateUI(result.user);
    });

    signInButton.addEventListener('click', function() {
        chrome.runtime.sendMessage({action: 'signIn'}, function(response) {
            if (response.user) {
                updateUI(response.user);
            }
        });
    });

    signOutButton.addEventListener('click', function() {
        chrome.runtime.sendMessage({action: 'signOut'}, function() {
            updateUI(null);
        });
    });
});

e) Create a background.js file in chrome-extension/background.js

const OFFSCREEN_DOCUMENT_PATH = 'offscreen.html';
const FIREBASE_HOSTING_URL = 'https://your-project-id.web.app'; // Replace with your Firebase hosting URL

let creatingOffscreenDocument;

async function hasOffscreenDocument() {
    const matchedClients = await clients.matchAll();
    return matchedClients.some((client) => client.url.endsWith(OFFSCREEN_DOCUMENT_PATH));
}

async function setupOffscreenDocument() {
    if (await hasOffscreenDocument()) return;

    if (creatingOffscreenDocument) {
        await creatingOffscreenDocument;
    } else {
        creatingOffscreenDocument = chrome.offscreen.createDocument({
            url: OFFSCREEN_DOCUMENT_PATH,
            reasons: [chrome.offscreen.Reason.DOM_SCRAPING],
            justification: 'Firebase Authentication'
        });
        await creatingOffscreenDocument;
        creatingOffscreenDocument = null;
    }
}

async function getAuthFromOffscreen() {
    await setupOffscreenDocument();
    return new Promise((resolve, reject) => {
        chrome.runtime.sendMessage({action: 'getAuth', target: 'offscreen'}, (response) => {
            if (chrome.runtime.lastError) {
                reject(chrome.runtime.lastError);
            } else {
                resolve(response);
            }
        });
    });
}

chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
    if (message.action === 'signIn') {
        getAuthFromOffscreen()
            .then(user => {
                chrome.storage.local.set({user: user}, () => {
                    sendResponse({user: user});
                });
            })
            .catch(error => {
                console.error('Authentication error:', error);
                sendResponse({error: error.message});
            });
        return true; // Indicates we will send a response asynchronously
    } else if (message.action === 'signOut') {
        chrome.storage.local.remove('user', () => {
            sendResponse();
        });
        return true;
    }
});

f) Create an offscreen.html file in chrome-extension/offscreen.html



    Offscreen Document

g) Create an offscreen.js file in _chrome-extension/offscreen.js
_

const FIREBASE_HOSTING_URL = 'https://your-project-id.web.app'; // Replace with your Firebase hosting URL

const iframe = document.createElement('iframe');
iframe.src = FIREBASE_HOSTING_URL;
document.body.appendChild(iframe);

chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
    if (message.action === 'getAuth' && message.target === 'offscreen') {
        function handleIframeMessage({data}) {
            try {
                const parsedData = JSON.parse(data);
                window.removeEventListener('message', handleIframeMessage);
                sendResponse(parsedData.user);
            } catch (e) {
                console.error('Error parsing iframe message:', e);
            }
        }

        window.addEventListener('message', handleIframeMessage);
        iframe.contentWindow.postMessage({initAuth: true}, FIREBASE_HOSTING_URL);
        return true; // Indicates we will send a response asynchronously
    }
});

Step 4: Configure Firebase Authentication

a) In the Firebase Console, go to Authentication > Sign-in method.
b) Enable Google as a sign-in provider.
c) Add your Chrome extension's ID to the authorized domains list:
The format is: chrome-extension://YOUR_EXTENSION_ID
You can find your extension ID in Chrome's extension management page after loading it as an unpacked extension.

Step 5: Load and Test the Extension

a) Open Google Chrome and go to chrome://extensions/.
b) Enable "Developer mode" in the top right corner.
c) Click "Load unpacked" and select your chrome-extension directory.
d) Click on the extension icon in Chrome's toolbar to open the popup.
e) Click the "Sign In" button and test the authentication flow.

Troubleshooting

If you encounter CORS issues, ensure your Firebase hosting URL is correctly set in both background.js and offscreen.js.

Make sure your Chrome extension's ID is correctly added to Firebase's authorized domains.

Check the console logs in the popup, background script, and offscreen document for any error messages.

Conclusion

You now have a Chrome extension that uses Firebase Authentication with an offscreen document to handle the sign-in process. This setup allows for secure authentication without exposing sensitive Firebase configuration details directly in the extension code.

Remember to replace placeholder values (like YOUR_EXTENSION_ID, YOUR-CLIENT-ID, YOUR_PUBLIC_KEY, and your-project-id) with your actual values before publishing your extension.

版本声明 本文转载于:https://dev.to/lvn1/google-authentication-in-a-chrome-extension-with-firebase-2bmo?1如有侵犯,请联系[email protected]删除
最新教程 更多>
  • Websocket 或 Socket io!让我们来看看吧!
    Websocket 或 Socket io!让我们来看看吧!
    WebSockets 与 Socket.IO:实时对决 当谈到网络上的实时通信时,开发人员经常发现自己陷入两个选择之间:WebSockets 和 Socket.IO。这两种工具都擅长它们的工作——提供了一种在客户端和服务器之间实现双向通信的方法——但每种工具都有自己独特的个性。这有...
    编程 发布于2024-11-02
  • Deno 起飞
    Deno 起飞
    网络是人类最大的软件平台,拥有超过 50 亿用户,并且还在不断增长。然而,随着 Web 开发需求的飙升,其复杂性也随之增加。在无尽的配置文件、大量的样板文件和大量的依赖项之间,开发人员花费更多的时间来进行设置,而不是构建下一个大东西。? 进入 Deno,这是一种用于 JavaScript 和 Typ...
    编程 发布于2024-11-02
  • 使用 Django Rest Framework 寻找海森堡
    使用 Django Rest Framework 寻找海森堡
    The idea The idea was to create a simple platform for DEA agents, to manage information about characters from the Breaking Bad/Better Call Sa...
    编程 发布于2024-11-02
  • 汤姆和杰瑞灯代码
    汤姆和杰瑞灯代码
    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, ...
    编程 发布于2024-11-02
  • 通过实践学习 TDD:在 Umbraco 的富文本编辑器中标记成员
    通过实践学习 TDD:在 Umbraco 的富文本编辑器中标记成员
    在我正在构建的系统中,我需要能够在网站的文本中提及 Umbraco 成员。为此,我需要构建 Umbraco 富文本编辑器的扩展:TinyMCE。 语境 作为内容编辑者,我想在消息或文章中标记成员,以便他们收到有关其新内容的通知。 我研究了类似的实现,例如 Slack 或 X 上的实现...
    编程 发布于2024-11-02
  • 如何在Python测试场景中模拟HTTP请求和响应?
    如何在Python测试场景中模拟HTTP请求和响应?
    Python 测试的模拟请求和响应在 Python 测试中,有必要模拟模块及其功能来控制执行流程并验证具体场景。其中,模拟 requests 模块通常用于测试依赖于 HTTP 请求的函数或方法。考虑一个包含以下代码的views.py 文件:def myview(request): res1 ...
    编程 发布于2024-11-02
  • 如何构建适用于 Windows、Linux 和 macOS 的 Python 条码扫描器
    如何构建适用于 Windows、Linux 和 macOS 的 Python 条码扫描器
    条形码扫描已成为从零售、物流到医疗保健等各个行业的重要工具。在桌面平台上,它可以快速捕获和处理信息,无需手动输入数据,从而节省时间并减少错误。在本教程中,我们将通过构建适用于 Windows、Linux 的 Python 条形码扫描仪 继续探索 Dynamsoft Capture Vision SD...
    编程 发布于2024-11-02
  • ## 如何在 Python 中创建不可变对象以及为什么 nametuple 是最好的方法?
    ## 如何在 Python 中创建不可变对象以及为什么 nametuple 是最好的方法?
    Python 中的不可变对象在 Python 中,不变性为保护数据完整性提供了一种有价值的机制。然而,创建不可变对象会带来一定的挑战。重写 setattr常见的方法是重写 setattr方法。然而,即使在 init 过程中也会调用此方法,因此它不适合创建不可变对象。子类化 Tuple另一种策略涉及对...
    编程 发布于2024-11-02
  • 最常被问到的 React 面试问题
    最常被问到的 React 面试问题
    如何优化 React 应用程序的性能? 1。组件应谨慎更新 实现 shouldComponentUpdate 或 React.memo 通过比较 props 或 states 来防止不必要的重新渲染。 2.使用功能组件和钩子 带钩子的功能组件通常比类组件性能更高。 3.延迟加载组件...
    编程 发布于2024-11-02
  • (Wordpress 初学者):仅将子域从托管转移(迁移)到另一个新托管。
    (Wordpress 初学者):仅将子域从托管转移(迁移)到另一个新托管。
    我只想从 Bluehost 托管转移(迁移)一个新托管(例如 Fastcomet 或 Chemicloud)的子域。 我想知道我迁移子域的步骤是否正确以及我应该做什么更改 DNS 内容...... ** 我的情况1:** – 主 Web 域(例如:forcleanworld.com)保留在 Blue...
    编程 发布于2024-11-02
  • 使用 Java 进行数据分析:信息处理初学者指南
    使用 Java 进行数据分析:信息处理初学者指南
    Java 是一种适用于数据分析的强大语言,它提供用于处理大型数据集和执行复杂分析的基础结构,包括:数据结构:用于存储和组织数据的集合,例如数组和列表。IO 流:用于读取和写入文件的对象。Java 集合框架:用于管理和操作数据结构的强大集合类库。使用 Java 进行数据分析的实际案例包括分析文本文件,...
    编程 发布于2024-11-02
  • 雇用自由 Python 开发人员时要避免的常见错误
    雇用自由 Python 开发人员时要避免的常见错误
    介绍 雇用合适的自由 Python 开发人员可以决定你的项目的成败。然而,许多企业在招聘过程中会犯一些常见的错误,这些错误可能会导致招聘延迟、成本超支和结果不佳。以下是如何避免这些陷阱并确保项目成功的方法。 没有明确定义项目要求 最常见的错误之一是在开始招聘流程之前...
    编程 发布于2024-11-02
  • AWS SAM Lambda 项目的本地开发服务器
    AWS SAM Lambda 项目的本地开发服务器
    现在我正在开发一个项目,其中使用 AWS lambda 作为请求处理程序构建 REST API。整个过程使用 AWS SAM 定义 lambda、层并将其连接到漂亮的 template.yaml 文件中的 Api 网关。 问题 在本地测试此 API 并不像其他框架那样简单。虽然 AW...
    编程 发布于2024-11-02
  • 什么是 React?
    什么是 React?
    最近,我决定通过注册 元前端开发人员专业证书将我的技能提升到一个新的水平。 专业化涵盖各种主题,从基本的 Web 开发语言(例如 HTML、CSS 和 JavaScript)到高级框架 React。 通过这篇文章和以下博客文章,我的目标是分享我在通过认证过程中的经验、学习和进步。 所以… ...
    编程 发布于2024-11-02
  • 如何在C++中实现虚拟运算符重载?
    如何在C++中实现虚拟运算符重载?
    虚拟运算符重载背景在 C 中,可以为自定义数据类型重载运算符,从而提供定制的行为。然而,允许多态行为的虚拟方法不能直接用于运算符重载。问题考虑创建一个虚拟运算符
    编程 发布于2024-11-02

免责声明: 提供的所有资源部分来自互联网,如果有侵犯您的版权或其他权益,请说明详细缘由并提供版权或权益证明然后发到邮箱:[email protected] 我们会第一时间内为您处理。

Copyright© 2022 湘ICP备2022001581号-3