如何将 Web 应用程序身份验证与 Chrome 扩展同步

问题描述 投票:0回答:1

我一直在从事一个涉及用户在我的主网络应用程序上注册的项目。该 Web 应用程序是使用 Nextjs 14 和新的应用程序路由器支持创建的,我使用了 next-auth (将用户会话保存在 cookie 中)来让用户登录。现在我想在我的 Web 应用程序和Chrome 扩展程序,例如,用户可以在主 Web 应用程序上进行身份验证,当用户在单独的选项卡上单击 Chrome 扩展程序时,我想确保 Chrome 扩展程序根据经过身份验证的路由显示。如果注册的话,它还应该能够向受保护的 api 路由发出请求。 我从后台开发工具检查了流行的 chrome 扩展的网络选项卡,它们似乎调用其 api 端点来检查身份验证状态,即它们不会将令牌保存在 cookie 或本地存储中来检查身份验证状态。 我怎样才能启用这样的功能,我尝试在网上查找教程,但还没有帮助

谢谢你:)

authentication google-chrome next.js google-chrome-extension next.js13
1个回答
0
投票

要通过扩展实现登录,您需要将一些东西放在一起:

  • a
    background worker
    将监视浏览器 cookie 的变化
  • a
    listener
    在扩展端,它将监听后台工作人员广播的事件。每个 Chrome 扩展程序将有一个实例,这意味着每个打开的选项卡都有一个实例。

background worker
每个运行的浏览器实例都有一个实例,这意味着只有一个事件源。它将在您的浏览器启动时启动,并在您的浏览器关闭时关闭(崩溃或手动停止除外)。

background.js

REACT_APP_NEXTAUTH_SECRET
与前端中使用的相同。遗憾的是,这是一种安全隐患,但我从未找到更好的方法来解码 cookie 以获取 JWT。如果您找到一种按原样使用 cookie 的方法,那就更好了。
REACT_APP_COOKIE_DOMAIN
REACT_APP_COOKIE_NAME
是您的应用程序所独有的,最好的查找方法是通过
console.log
cookie 更改并查看其值。当您登录网站时,您应该输入更改 cookie 的值。

// Notify each extension instance of the cookie change
function broadcastMessageToAllTabs(message: object) {
  chrome.tabs.query({ status: "complete" }, (tabs) => {
    tabs.forEach((tab) => {
      if (tab.id) {
        chrome.tabs
          .sendMessage(tab.id, message)
          .catch((e) =>
            console.error(
              `Could not send message to the tab [${tab.id}/${tab.title}]`,
              e,
            ),
          );
      }
    });
  });
}

// Decodes the token contained within the cookie
async function setToken(token: string | null) {
  const decoded = token
    ? ((await decode({
        token,
        secret: process.env.REACT_APP_NEXTAUTH_SECRET as string,
      })) as { user: { accessToken: string } })
    : undefined;
  broadcastMessageToAllTabs({ token: decoded?.user?.accessToken || null });
}

// Adds a listener for cookies changing in the browser, e.g. after login or logout
chrome.cookies.onChanged.addListener(async (reason) => {
  if (
    reason.cookie.domain === process.env.REACT_APP_COOKIE_DOMAIN &&
    reason.cookie.name === process.env.REACT_APP_COOKIE_NAME
  ) {
    // On overwrite, removed is also true when it is actually updating the cookie, so we avoid to remove it for flickering
    await setToken(
      reason.removed && reason.cause !== "overwrite"
        ? null
        : reason.cookie.value,
    );
  }
});

my-plugin.ts

在扩展代码中的任何位置,您都应该为后台工作人员广播的更改添加侦听器。

  const handleMessage = (message: any) => {
    if ("token" in message) {
      // Got the token from the worker, save it somewhere so you can use it
    }
  };

  chrome.runtime.onMessage.addListener(handleMessage);
  // Ideally somewhere if you are releasing resources it is good to unsubscribe within your extension to avoid memory leaks and issues
  // chrome.runtime.onMessage.removeListener(handleMessage);

这部分应该可以帮助您在登录和退出网站时开始。现在还有一种情况没有被涵盖,那就是如果您已经登录并打开一个新选项卡。您的扩展程序将不会收到任何登录事件,因为您已经收到了,这将要求您每次打开选项卡时重新登录。

为了解决这个问题,我们应该实现从扩展到后台工作者的通信。在

background.ts
中,我们添加

// Listens to messages broadcasted, and eventually answers with the current cookie if any
chrome.runtime.onMessage.addListener(function (request, sender, sendResponse) {
  (async function () {
    if (request.type === "GET_COOKIE") {
      const cookie = await chrome.cookies.getAll({
        domain: process.env.REACT_APP_COOKIE_DOMAIN,
        name: process.env.REACT_APP_COOKIE_NAME,
      });
      if (cookie.length) {
        const decoded = cookie[0].value
          ? ((await decode({
              token: cookie[0].value,
              secret: process.env.REACT_APP_NEXTAUTH_SECRET as string,
            })) as { user: { accessToken: string } })
          : undefined;
        sendResponse({ token: decoded?.user?.accessToken || null });
        return;
      }
    }
    sendResponse({ token: null });
  })();
  return true;
});

并且在

my-plugin.ts
内,应在扩展实例启动时随时调用

chrome.runtime.sendMessage({ type: "GET_COOKIE" }, (response) => {
          if (response) {
            // Got a response from the worker, eventually sending us the token
          } else {
            console.error("Got an empty response for GET_COOKIE");
          }
        });

专业提示:为了帮助您调试和了解正在发生的情况,您还可以通过转到 Chrome 内部的设置/扩展来打开后台工作人员的控制台,然后打开您自己的扩展(这里是使用 React Dev Tools 的任意示例) ):

© www.soinside.com 2019 - 2024. All rights reserved.