我们如何使用 Google 和 Outlook OAuth 弹出窗口 我们如何实现它

2025-06-04

我们如何使用 Google 和 Outlook OAuth 弹出窗口

我们如何实现它

Leave Me Alone,我们使用 Google 和 Microsoft OAuth 进行用户登录。为此,我们将用户重定向到相关的登录页面,用户输入其详细信息,然后被引导回我们的网站并登录。这样做的一个不幸的结果是,我们的分析报告显示大量引荐流量来自“accounts.google.com”和“login.microsoft.com”。

我们如何使用 Google 和 Outlook OAuth 弹出窗口

为了解决这个问题,与其进行重定向,不如为 OAuth 流程打开一个新窗口或弹出窗口。而且,这可能比重定向到其他地方更有利于用户体验。

我们如何实现它

我们使用Passport进行身份验证,因此当用户登录后被引导回我们的应用程序时,URL 包含我们需要的一些参数,包括我们用来在服务器上对其进行身份验证的令牌。

由于我们想要使用弹出窗口,因此我们需要在流程中间添加一个步骤来捕获重定向、检索 URL 参数、关闭弹出窗口并在打开的窗口(而不是弹出窗口)中使用令牌。

我们如何使用 Google 和 Outlook OAuth 弹出窗口

我们允许用户使用 Google 和 Outlook 登录,两者的实现方式相同。为了方便阅读,本示例将以 Google 为例。

步骤 1:打开弹出窗口

要打开新窗口,我们使用Window.open()函数,传入 Passport 登录 URL(本例中为 /auth/google),它会在新窗口中打开“登录到 Leave Me Alone with Google”页面。我们还会为窗口命名,并传入我们想要的功能。

我们分配窗口引用并记录之前的 URL,这样即使用户再次尝试点击登录按钮,即使登录的是不同的提供商,系统也会使用或聚焦同一个窗口。我们不希望两个不同提供商的弹窗四处浮动,造成混淆。

最后,我们添加一个消息事件监听器,因为弹出窗口将在完成时发送 URL 参数和身份验证令牌。

let windowObjectReference = null;
let previousUrl = null;
const openSignInWindow = (url, name) => {
// remove any existing event listeners
window.removeEventListener('message', receiveMessage);
// window features
const strWindowFeatures =
'toolbar=no, menubar=no, width=600, height=700, top=100, left=100';
if (windowObjectReference === null || windowObjectReference.closed) {
/* if the pointer to the window object in memory does not exist
or if such pointer exists but the window was closed */
windowObjectReference = window.open(url, name, strWindowFeatures);
} else if (previousUrl !== url) {
/* if the resource to load is different,
then we load it in the already opened secondary window and then
we bring such window back on top/in front of its parent window. */
windowObjectReference = window.open(url, name, strWindowFeatures);
windowObjectReference.focus();
} else {
/* else the window reference must exist and the window
is not closed; therefore, we can bring it back on top of any other
window with the focus() method. There would be no need to re-create
the window or to reload the referenced resource. */
windowObjectReference.focus();
}
// add the listener for receiving a message from the popup
window.addEventListener('message', event => receiveMessage(event), false);
// assign the previous URL
previousUrl = url;
};
view raw open-popup.js hosted with ❤ by GitHub
let windowObjectReference = null;
let previousUrl = null;
const openSignInWindow = (url, name) => {
// remove any existing event listeners
window.removeEventListener('message', receiveMessage);
// window features
const strWindowFeatures =
'toolbar=no, menubar=no, width=600, height=700, top=100, left=100';
if (windowObjectReference === null || windowObjectReference.closed) {
/* if the pointer to the window object in memory does not exist
or if such pointer exists but the window was closed */
windowObjectReference = window.open(url, name, strWindowFeatures);
} else if (previousUrl !== url) {
/* if the resource to load is different,
then we load it in the already opened secondary window and then
we bring such window back on top/in front of its parent window. */
windowObjectReference = window.open(url, name, strWindowFeatures);
windowObjectReference.focus();
} else {
/* else the window reference must exist and the window
is not closed; therefore, we can bring it back on top of any other
window with the focus() method. There would be no need to re-create
the window or to reload the referenced resource. */
windowObjectReference.focus();
}
// add the listener for receiving a message from the popup
window.addEventListener('message', event => receiveMessage(event), false);
// assign the previous URL
previousUrl = url;
};
view raw open-popup.js hosted with ❤ by GitHub

为了让窗口以弹出窗口而不是新选项卡的形式打开,我们必须请求这些功能menubar=no,toolbar=no

步骤 2:在弹出窗口中获取 OAuth 回调参数

OAuth 流程完成后,Google 会将用户重定向到一个回调 URL。通常,这是一个执行 Passport 身份验证的服务器路由。由于身份验证是在弹窗中进行的,因此我们在应用中使用了一个页面,该页面在加载时会抓取搜索参数并将其发送给父级。

此回调页面使用React Use Effect Hook,该 Hook 在页面加载时执行。我们获取包含身份验证令牌的 URL 参数,并使用Window.postMessage()将其发送到正在打开的窗口(父窗口) 。

步骤 3:验证用户身份并重定向到应用程序

OAuth 流程几乎完成,弹出窗口现已关闭,我们只需要在我们的服务器上对用户进行身份验证。

出于安全考虑,接收消息函数需要检查消息来源,以确保其来自同一域。在编写代码时,我们意识到一些 Chrome 开发者工具使用来自同一域的 postMessage() 函数,因此在尝试提取有效载荷之前,我们也会检查消息来源。

一旦我们有了 OAuth 参数,我们就会将用户重定向到我们自己的身份验证端点,以便我们可以使用 Passport 进行身份验证和登录。

完成的!

这个过程非常简单,我们所做的就是在 OAuth 流中添加一个中间步骤来传递回调参数。

可能有很多实现,但对于我们来说,使用 React.js 是最快、最简单的。


希望这对您有所帮助或为您自己的解决方案提供一些启发。

如果您有任何问题或建议,请告诉我们!

文章来源:https://dev.to/dinkydani21/how-we-use-a-popup-for-google-and-outlook-oauth-oci
PREV
CORS(跨域资源共享)如何工作?
NEXT
Next.js:Firebase 身份验证和 API 路由中间件