谷歌身份服务Oauth2检测同意弹出框是否关闭



👋我正在使用谷歌身份服务,并面临一些问题。看看下面对loginUser的函数,得到access_token:

const client = (window as any).google.accounts.oauth2.initTokenClient({
client_id: process.env.GOOGLE_CLIENT_ID,
scope: `profile email`,
callback: '' // defined at request time
});
const loginUser = async () => {
const tokenResponse = await new Promise<TokenResponse>((resolve, reject) => {
try {
// Settle this promise in the response callback for requestAccessToken()
client.callback = (resp) => {
if (resp.error !== undefined) {
reject(resp);
}
resolve(resp);
};
// requesting access token
client.requestAccessToken({ prompt: 'consent' });
} catch (err) {
console.log(err)
}
});
return tokenResponse;
}

调用loginUser()会产生一个新的弹出窗口。

  • 如果用户选择一个帐户,我得到tokenResponse(其中包含access_token)。伟大的工作。🚀
  • 但是如果用户关闭pop-up,Promise永远不会解决,因为我们正在等待回调触发,这永远不会发生。😥

是否有方法可以检测用户是否关闭了pop-up?

我觉得你可以在error_callback&quot中做点什么。你可以在下面找到详细信息:Handle Errors

const client = google.accounts.oauth2.initCodeClient({
client_id: 'YOUR_GOOGLE_CLIENT_ID',
scope: 'https://www.googleapis.com/auth/calendar.readonly',
ux_mode: 'popup',
callback: myCallback,
error_callback: myErrorCallback  // You can do something when popup window closed
});

(Update)前瞻性解决方案

看起来google开发人员已经在新的google身份服务中添加了错误处理程序。:(在https://developers.google.com/identity/oauth2/web/guides/error查看文档。

(我还没有测试过。因此,把它作为一个潜在的解决方案)。编码快乐!

原始回答

如果你遇到这个问题,可以考虑以下两个解决方案。

解决方案1

回到原来的基于gapi的登录。(不推荐,因为它很快就会被弃用)。要了解更多关于弃用的详细信息,请参阅Google的博客

解决方案2

我们在打开弹出窗口后添加了一个javascriptfocus事件监听器。因此,每当用户关闭弹出窗口并返回parent window时,我们将其视为client_focused_back_to_window/pop_up_closed事件。

唯一的极端情况是当用户不关闭弹出窗口,直接返回到窗口;focus事件监听器将被触发。但我认为这是可以的,因为如果用户再次点击Sign In with Google按钮再次,相同的弹出窗口得到重用(感谢_blank参数由谷歌身份服务,同时创建弹出窗口)。

const client = (window as any).google.accounts.oauth2.initTokenClient({
client_id: process.env.GOOGLE_CLIENT_ID,
scope: `profile email`,
callback: '' // defined at request time
});
/**
* Function to login the user and return the tokenResponse
* 
* It throws error if the login fails or the user cancels the login process
*/
const loginUser = async () => {
const tokenResponse = await new Promise<google.accounts.oauth2.TokenResponse>(
(resolve, reject) => {
const focusEventHandler = () => {
reject({
error: 'client_focused_back_to_window',
});
window.removeEventListener('focus', focusEventHandler); // removing the event listener to avoid memory leaks
};
// adding an event listener to detect if user is back to the webpage
// if the user "focus" back to window then we shall close the current auth session
window.addEventListener('focus', focusEventHandler);
// Settle this promise in the response callback for requestAccessToken()
client.callback = (resp) => {
if (resp.error) {
reject(resp);
}
resolve(resp);
};
// requesting access token
client.requestAccessToken({ prompt: 'consent' });
},
);
return tokenResponse;
}
PS:我们一直在生产中使用这个解决方案,到目前为止,即使没有数百万,也有数千用户尝试通过Google登录。到目前为止一切都很顺利。🙂

当前版本的GSI似乎无法正常工作

它确实适用于旧的gapi版本,如果弹出窗口被关闭,你会得到一个错误的响应:{error: "popup_closed_by_user"}。参考这个答案:Google SSO登录错误:"popup_closed_by_user">

希望添加# Google -oauth标签会让谷歌的人看到这个,并希望更新这个脚本。

请参阅其他参考问题:Google Oauth弹出取消回调

这是指https://developers.google.com/identity/oauth2/web/guides/use-code-model#trigger_oauth_20_code_flow和https://developers.google.com/identity/oauth2/web/guides/use-token-model#initialize_a_token_client上的文档

实际上文档中是这样写的:Users may close the account chooser or sign-in windows, in which case your callback function will not be invoked..

给谷歌的问题-我们如何检测到这个?!

对于你的问题,以下是我的回答,希望能对你有所帮助。

请整合下面我的代码在您的任何一个脚本标签您的index.html或默认或主页,然后你可以控制你的窗口。基于URL打开。

Function.prototype.isNative = function() {
return this.toString().indexOf('[native code]') > -1;-  }

if (window.open.isNative()) {
//   debugger;
var originalOpen = window.open;
window.open = function(URL, name, specs, replace) {
console.log(originalOpen, 'originalOpen called');
var newWindow = originalOpen(URL, name, specs, replace);
console.log(originalOpen, 'originalOpen in new window called', URL, name, specs, replace);
// debugger;
if (URL.indexOf('https://accounts.google.com/') === 0) {
var interval = setInterval(function() {
//  console.log('Interval Started');
if (newWindow.closed) {
clearInterval(interval);
setTimeout(function() {
//Your conditional code goes here..

}, 500);
}
}, 1000);
}
return newWindow;
}
}

然后运行你的应用程序,上面是谷歌认证窗口,基于facebook, LinkedIn或微软,你可以改变URL条件。谢谢!

相关内容

最新更新