Firebase + Chrome扩展程序:保持身份验证状态

5
我正在尝试在Chrome扩展中设置身份验证。我希望用户只需单击扩展图标,使用电子邮件和密码进行登录,然后能够使用扩展的不同组件。如果关闭了扩展弹出窗口,他们就不必再次登录。
我一直在仔细遵循文档这里这里特定于Chrome扩展的文档,但我的开发经验非常有限。
这是我的manifest.json
{
  "name": "Extension",
  "version": "0.1",
  "description": "",
  "permissions": [
    "tabs",
    "activeTab",
    "storage"
  ],
  "content_security_policy": "script-src 'self' https://www.gstatic.com/ https://*.firebaseio.com https://*.firebase.com https://www.googleapis.com; object-src 'self'",
  "background": {
    "page":"background.html",
    "persistent": true
  },
  "browser_action": {
    "default_popup": "popup.html",
    "default_icon": {}
  },
  "manifest_version": 2
}

我的background.htmlbackground.js与我上面链接的最后一个示例严格相同,除了当然我用自己的Firebase配置替换它。

我的popup.html是:

<!DOCTYPE html>
<html lang="en" dir="ltr">

  <head>
    <meta charset="utf-8">
    <title></title>
    <script src="https://www.gstatic.com/firebasejs/5.10.0/firebase.js"></script>
    <script src="firebase/initialize.js" charset="utf-8"></script>
    <script src="https://cdn.firebase.com/libs/firebaseui/3.5.2/firebaseui.js"></script>
    <link type="text/css" rel="stylesheet" href="https://cdn.firebase.com/libs/firebaseui/3.5.2/firebaseui.css"/>
    <link type="text/css" rel="stylesheet" href="styles/popup.css" />
  </head>

  <body>
    <h1>Extension</h1>
    <div id="firebaseui-auth-container"></div>
    <!-- Firebase App (the core Firebase SDK) is always required and must be listed first -->
    <script src="src/popup.js"></script>
  </body>

</html>

其中,initialize.js仅是Firebase初始化脚本,而我的popup.js则为:

//Initizalier FirebaseUI instance
var ui = new firebaseui.auth.AuthUI(firebase.auth());
//Define sign-in methods
var uiConfig = {
  callbacks: {
    //Callbacl if sign up successful
    signInSuccessWithAuthResult: function(authResult) {
      // User successfully signed in.
      // Return type determines whether we continue the redirect automatically
      // or whether we leave that to developer to handle.

      //Script to replace popup content with my Extension UI

      return false;
    },
  },
  signInOptions: [
    {
      provider: firebase.auth.EmailAuthProvider.PROVIDER_ID,
      requireDisplayName: false
    }
  ],
};

//Initialize UI
ui.start('#firebaseui-auth-container', uiConfig);

使用这个扩展,我可以说每次单击扩展图标时登录都有效,但是如果我关闭并重新打开弹出窗口,则需要再次登录。我已经在各个地方询问过这个问题。我还尝试向我的background.js脚本询问此stackoverflow问题的答案,但没有成功。
如果我没有完全迷失,我想我知道为什么会这样。如果我没有错,浏览器操作弹出窗口会覆盖后台页面/脚本正在执行的操作。然而,我不确定应该修改什么。我也看了一下在Chrome扩展中使用Firebase进行身份验证,但我无法理解它如何适用于我的工作。
现在我不知道接下来该怎么做了。

弹出窗口的环境仅在显示时存在。 - wOxxOm
@wOxxOm,我也是这么想的,但我不知道如何在这种情况下使用Firebase登录UI。肯定有方法可以做到这一点,也许与背景脚本有关…… 我仍然不知道。 - Experience111
1个回答

8
我已经找到了解决问题的方法。我链接中提到的@cloop的答案是正确的,但为了那些以后会遇到这个问题的人,我将用自己的方式来解释。我希望这样更适合初学者,因为我本身不是开发人员。
请注意,这仅是我拥有MVP的解决方案,很可能有更好的方法来解决这个问题。
首先,不要使用Firebase UI库,因为它与Chrome扩展不兼容。我假设您已经阅读了Chrome Extension tutorial以及Firebase Authentication文档的基础知识。
现在我们必须放弃我们迄今为止所做的一切,并从一个空的扩展开始。我们将为其设置电子邮件+密码验证。
首先,我们创建清单:
{
  "name": "Test extension",
  "version": "0.1",
  "description": "An extension to test Firebase auth",
  "permissions": [/*Insert necessary permissions*/],
  "content_security_policy": "script-src 'self' https://www.gstatic.com/ https://*.firebaseio.com https://*.firebase.com https://www.googleapis.com; object-src 'self'",
  "background": {
    "page":"background.html",
    "persistent": true
  },
  "browser_action": {
    "default_popup": "popup.html",
  },
  "manifest_version": 2
}

background.html是与background.js脚本链接的后台页面。这是因为我们必须在页面的<head>中加载firebase,然后才能在脚本中初始化它,例如请参见这里的脚本。 popup.html将是我们根据身份验证状态动态加载的页面。它链接到一个脚本popup.js,只包含一个div元素#container。我们将立即向该弹出窗口添加事件侦听器,使用Messaging API向后台脚本发送消息。

window.addEventListener('DOMContentLoaded', (_event) => {
  console.log("DOM loaded and parsed");
  //Send a message to background script informing that the page is loaded
  chrome.runtime.sendMessage({type: "popupLoad"}, function (response) {
       if (response.type == "loggedIn") {
           let htmlString = /*Your extension UI's HTML*/;
           document.querySelector("#container").innerHTML(htmlString);
       } else if (response.type == "loggedOut") {
           let htmlString = /*Log in form HTML*/
           document.querySelector("#container").innerHTML(htmlString);
       };
  });

这里我们所做的是在我们的 popup.html 完全加载完毕时向后台脚本发送一条消息,以查询身份验证状态。后台脚本将向我们发送一个类型为 loggedInloggedOutresponse 对象,让我们决定应该为我们的弹出窗口加载哪个界面。
现在我们看看后台脚本。
首先,您应该初始化 Firebase。
var config = {
    /*Your config parameters from the Firebase console*/
  };
firebase.initializeApp(config);

现在我们需要添加一个消息监听器。请注意,这将监听任何Chrome环境(选项卡、窗口、弹出脚本等)发送的任何消息,因此我们必须确保我们正在处理正确类型的消息。这就是为什么我在弹出脚本消息创建中使用了{type: "popupLoad"}。所有我的消息至少都有一个type属性。
chrome.runtime.onMessage.addListener(
    function(message, _sender, _sendResponse) {
      if (message.type == "popupLoad") {
        //Get current authentication state and tell popup
        let user = firebase.auth().currentUser;
        if (user) {
          sendResponse({type: "loggedIn"});
        } else {
          sendResponse({type: "loggedOut"});
        };
      } else if (message.type == "other") {
          //handle other types of messages
      };
    });

我们已经完成的工作是,当用户点击扩展图标时,我们能够根据认证状态决定弹出窗口的界面。当然,如果用户未登录,则会看到我们的登录/注册表单。该表单的按钮应具有事件侦听器,发送一条消息(例如loginAttempt类型)到后台脚本,然后后台脚本应对弹出脚本进行响应,如果登录成功,则允许我们替换#container内容为我们扩展的UI。在这里,我们可以看到扩展实际上是一个单页应用程序。
我不得不在后台脚本中使用firebase.auth().onAuthStateChanged()方法,它基本上是一个事件侦听器,如果我没记错的话,它检测认证状态的更改。
我不会深入讨论,但我希望这对像我一样的初学者足以理解并设计一个可行的原型。
简而言之:
  • 不要使用Firebase UI库
  • 在后台脚本中初始化Firebase
  • 扩展程序是单页面应用程序。使用Messaging API从后台脚本获取当前身份验证状态或身份验证状态更改,以便能够决定要为用户提供什么界面

如果有人注意到这个答案有任何问题,请不要犹豫。一些功劳归功于许多善良的人,在dev Discord上帮助过我,或者我随意向他们发送电子邮件,并使我走上了正确的轨道。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接