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

93ze6v8z  于 2024-01-07  发布在  其他
关注(0)|答案(1)|浏览(100)

我一直在做一个项目,涉及用户在我的主Web应用程序上注册。(将用户会话保存在cookie中)以使用户登录。现在我想在我的Web应用程序和Chrome扩展程序之间同步身份验证状态,例如,用户可以在主web应用上进行认证并且当用户在单独的选项卡上点击Chrome扩展时,我想确保Chrome扩展程序显示基于认证的路由。如果注册,它也应该能够向受保护的API路由发出请求。我检查了流行的Chrome的网络选项卡从后台开发工具的扩展,似乎他们调用他们的API端点来检查身份验证的状态,即他们不保存令牌在cookie或本地存储来检查身份验证状态。我如何才能启用这样的东西,我试着在网上找到教程,但还没有帮助
Thank you:)

ggazkfy8

ggazkfy81#

要通过扩展实现登录,您需要将几件事放在一起:

  • 一个background worker,它将监视您浏览器cookie的变化
  • 一个listener在扩展端,它将监听你的后台工作进程广播的事件。每个Chrome扩展将有一个示例,这意味着每个打开的标签页一个示例。

background worker将为每个运行的浏览器示例提供一个示例,这意味着只有一个事件源。它将在浏览器启动时启动,并在浏览器关闭时关闭(崩溃或手动停止除外)。
background.js
REACT_APP_NEXTAUTH_SECRET和你的前端使用的是同一个。可悲的是,这是一种安全隐患,但我从来没有找到一个更好的方法来解码cookie来获得JWT。如果你找到一种方法来使用cookie,它是更好的。REACT_APP_COOKIE_DOMAINREACT_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
在扩展代码中的任何地方,您都应该为后台worker广播的更改添加一个侦听器。

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);


这部分应该让你开始当你登录和退出你的网站.现在有一个额外的情况下,它没有涵盖,这是如果你已经登录并打开一个新的标签.您的扩展将不会收到任何登录事件,因为你已经这样做,这将需要你再次登录,每次打开一个标签.
为了解决这个问题,我们应该实现从扩展到后台worker的通信。

// 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的任意示例):x1c 0d1x

相关问题