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
浏览:651

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]删除
最新教程 更多>
  • 为什么Microsoft Visual C ++无法正确实现两台模板的实例?
    为什么Microsoft Visual C ++无法正确实现两台模板的实例?
    [2明确担心Microsoft Visual C(MSVC)在正确实现两相模板实例化方面努力努力。该机制的哪些具体方面无法按预期运行?背景:说明:的初始Syntax检查在范围中受到限制。它未能检查是否存在声明名称的存在,导致名称缺乏正确的声明时会导致编译问题。为了说明这一点,请考虑以下示例:一个符合...
    编程 发布于2025-02-19
  • 如何可靠地检查MySQL表中的列存在?
    如何可靠地检查MySQL表中的列存在?
    在mySQL中确定列中的列存在,验证表中的列存在与与之相比有点困惑其他数据库系统。常用的方法:如果存在(从信息_schema.columns select * * where table_name ='prefix_topic'和column_name =&...
    编程 发布于2025-02-19
  • Java是否允许多种返回类型:仔细研究通用方法?
    Java是否允许多种返回类型:仔细研究通用方法?
    在java中的多个返回类型:一个误解介绍,其中foo是自定义类。该方法声明似乎拥有两种返回类型:列表和E。但是,情况确实如此吗?通用方法:拆开神秘 [方法仅具有单一的返回类型。相反,它采用机制,如钻石符号“ ”。分解方法签名: :本节定义了一个通用类型参数,E。它表示该方法接受扩展FOO类的任何...
    编程 发布于2025-02-19
  • 为什么使用固定定位时,为什么具有100%网格板柱的网格超越身体?
    为什么使用固定定位时,为什么具有100%网格板柱的网格超越身体?
    网格超过身体,用100%grid-template-columns 问题:考虑以下CSS和HTML: position:fixed; grid-template-columns:40%60%; grid-gap:5px; 背景:#eee; 当位置未固定时,网格将正确显示。但是,当...
    编程 发布于2025-02-19
  • 在没有密码提示的情况下,如何在Ubuntu上安装MySQL?
    在没有密码提示的情况下,如何在Ubuntu上安装MySQL?
    在ubuntu 使用debconf-set-selections 在安装过程中避免密码提示mysql root用户。这需要以下步骤: sudo debconf-set-selections
    编程 发布于2025-02-19
  • 如何使用组在MySQL中旋转数据?
    如何使用组在MySQL中旋转数据?
    在关系数据库中使用mysql组使用mysql组来调整查询结果。在这里,我们面对一个共同的挑战:使用组的组将数据从基于行的基于列的基于列的转换。通过子句以及条件汇总函数,例如总和或情况。让我们考虑以下查询: select d.data_timestamp, sum(data_id = 1 tata...
    编程 发布于2025-02-19
  • \“(1)vs.(;;):编译器优化是否消除了性能差异?\”
    \“(1)vs.(;;):编译器优化是否消除了性能差异?\”
    答案:在大多数现代编译器中,while(1)和(1)和(;;)之间没有性能差异。 说明: perl: S-> 7 8 unstack v-> 4 -e语法ok 在GCC中,两者都循环到相同的汇编代码中,如下所示:。 globl t_时 t_时: .l2: movl $ .lc0,�i ...
    编程 发布于2025-02-19
  • 为什么箭头函数在IE11中引起语法错误?如何修复它们?
    为什么箭头函数在IE11中引起语法错误?如何修复它们?
    为什么arrow functions在IE 11 中引起语法错误。 IE 11不支持箭头函数,导致语法错误。这使用传统函数语法来定义与原始箭头函数相同的逻辑。 IE 11现在将正确识别并执行代码。
    编程 发布于2025-02-19
  • 'exec()
    'exec()
    Exec对本地变量的影响: exec function,python staple,用于动态代码执行的python staple,提出一个有趣的Query:它可以在函数中更新局部变量吗?在Python 3中,以下代码代码无法更新本地变量,如人们所期望的:代替预期的'3',它令人震...
    编程 发布于2025-02-19
  • 如何从Python中的字符串中删除表情符号:固定常见错误的初学者指南?
    如何从Python中的字符串中删除表情符号:固定常见错误的初学者指南?
    从python 导入编解码器 导入 text = codecs.decode('这狗\ u0001f602'.encode('utf-8'),'utf-8') 印刷(文字)#带有表情符号 emoji_pattern = re.compile(“ [”...
    编程 发布于2025-02-19
  • 如何检查对象是否具有Python中的特定属性?
    如何检查对象是否具有Python中的特定属性?
    方法来确定对象属性存在寻求一种方法来验证对象中特定属性的存在。考虑以下示例,其中尝试访问不确定属性会引起错误: >>> a = someClass() >>> A.property Trackback(最近的最新电话): 文件“ ”,第1行, AttributeError:SomeClass实...
    编程 发布于2025-02-19
  • 如何在JavaScript对象中动态设置键?
    如何在JavaScript对象中动态设置键?
    如何为JavaScript对象变量创建动态键,尝试为JavaScript对象创建动态键,使用此Syntax jsObj['key' i] = 'example' 1;将不起作用。正确的方法采用方括号:他们维持一个长度属性,该属性反映了数字属性(索引)和一个数字属性的数量。标准对象没有模仿这...
    编程 发布于2025-02-19
  • 版本5.6.5之前,使用current_timestamp与时间戳列的current_timestamp与时间戳列有什么限制?
    版本5.6.5之前,使用current_timestamp与时间戳列的current_timestamp与时间戳列有什么限制?
    在默认值中使用current_timestamp或mysql版本中的current_timestamp或在5.6.5 这种限制源于遗产实现的关注,这些限制需要为Current_timestamp功能提供特定的实现。消息和相关问题 current_timestamp值: 创建表`foo`( `...
    编程 发布于2025-02-19
  • 如何使用PHP从XML文件中有效地检索属性值?
    如何使用PHP从XML文件中有效地检索属性值?
    从php 您的目标可能是检索“ varnum”属性值,其中提取数据的传统方法可能会使您留下PHP陷入困境。使用simplexmlelement :: attributes()函数提供了简单的解决方案。此函数可访问对XML元素作为关联数组的属性: - > attributes()为$ attr...
    编程 发布于2025-02-19
  • 哪种方法更有效地用于点 - 填点检测:射线跟踪或matplotlib \的路径contains_points?
    哪种方法更有效地用于点 - 填点检测:射线跟踪或matplotlib \的路径contains_points?
    在Python 射线tracing方法 matplotlib路径对象表示多边形。它检查给定点是否位于定义路径内。 This function is often faster than the ray tracing approach, as seen in the code snippet pr...
    编程 发布于2025-02-19

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

Copyright© 2022 湘ICP备2022001581号-3