Outlook插件提取认证弹窗URL中ID Token遇跨域报错求解决方案
解决Outlook插件提取ID Token的跨域安全错误
问题原因
你遇到的Uncaught DOMException是浏览器同源策略导致的:当弹窗跳转到IDP的认证域后,你的Outlook插件页面(父窗口)和弹窗页面属于不同域名,浏览器禁止父窗口访问不同域弹窗的location.href属性,以此防止跨域数据泄露。
可行解决方案
改用同域回调页面 + postMessage的方式,绕开同源限制,具体步骤如下:
1. 配置IDP重定向地址
修改IDP的认证配置,将认证成功后的重定向地址设置为一个和你的Outlook插件完全同域的静态页面(比如callback.html),确保协议、域名、端口完全一致。
2. 修改父窗口(插件页面)代码
移除轮询弹窗URL的逻辑,改为监听来自回调页面的消息:
function determineAuthenticationMethodAndRedirect(data, tenantId) { if (data.IdentityProvider.Enabled) { console.log("Identity Provider authentication is enabled"); // 构造认证URL,指定同域回调地址 const baseAuthUrl = Office.context.roamingSettings.get("userInput") + "/Apps/Erp/Home/"; const callbackUrl = encodeURIComponent(window.location.origin + "/callback.html"); const authUrl = `${baseAuthUrl}?redirect_uri=${callbackUrl}&tenantId=${tenantId}`; openPopup(authUrl); } else if (data.TokenAuthentication.Enabled) { console.log("Token-based authentication is enabled"); window.location.href = "ep-collab-login.js"; } else if (data.BasicAuthentication.Enabled) { console.log("Basic authentication is enabled"); } else { console.log("No supported authentication method is enabled"); } } function openPopup(url) { const popupWidth = 600; const popupHeight = 400; const popupSettings = `width=${popupWidth},height=${popupHeight},top=${(window.innerHeight - popupHeight)/2},left=${(window.innerWidth - popupWidth)/2},scrollbars=yes,resizable=yes`; const popup = window.open(url, "_blank", popupSettings); // 监听回调页面发送的消息 window.addEventListener("message", (event) => { // 验证消息来源,避免恶意消息 if (event.origin !== window.location.origin) return; if (event.data.type === "ID_TOKEN_RECEIVED") { const idToken = event.data.token; if (idToken) { console.log('ID Token:', idToken); // 这里可以加入后续API调用逻辑 } else { console.log('ID Token not available'); } popup.close(); } }); }
3. 创建同域回调页面(callback.html)
这个页面负责提取URL中的ID Token,并通过postMessage发送给父窗口:
<!DOCTYPE html> <html> <head> <script> function extractIdTokenFromUrl(url) { const match = url.match(/[?&]id-token=([^&]*)/); return match ? decodeURIComponent(match[1]) : null; } window.onload = () => { const idToken = extractIdTokenFromUrl(window.location.href); // 向父窗口发送Token window.opener.postMessage( { type: "ID_TOKEN_RECEIVED", token: idToken }, window.opener.location.origin ); // 自动关闭页面 setTimeout(() => window.close(), 500); }; </script> </head> <body> <p>认证处理中,请稍候...</p> </body> </html>
关键注意事项
- 回调页面必须和插件页面完全同源,否则
postMessage会被浏览器拦截 - 务必在IDP的允许重定向列表中添加这个回调页面地址,否则IDP会拒绝跳转
- 不要尝试直接访问跨域弹窗的
location属性,这是浏览器安全策略明确禁止的行为
内容的提问来源于stack exchange,提问作者Pearl
相关产品推荐
相关产品推荐

