重温一下第三方登录流程:

  1. 访问登录页;
  2. 点击第三方登录,跳到对应的第三方登录页;
  3. 授权登录后,原登录页刷新、跳转到登录后的成功页(来源页,or,后台管理页);
  4. 关闭打开的第三方登录后的回调页,over。

原本正常的第三方登录,在增加了来源页的判断后,却产生了问题:在Safari下被浏览器拦截,告知权限问题:

SecurityError: Blocked a frame with origin "http://www.example.com" from accessing a cross-origin frame.

另一个是关于pop-up被拦截的问题,都是因为Safari的安全策略所导致的。此处,便是由于对window.opener.location.href的访问和修改,导致了被Safari拦截。

如何解决呢?

联想到曾经在解决跨窗口(window.open,or,iframe)间的通信问题时,使用过postMessage方式,这应该就是处理此问题的最佳方案了。

原来的跳转代码:

typescriptCopy code
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
const urlSearch = new URL(window.opener.location.href).search.split('?'); let referer = ''; if (urlSearch.length > 1) { const temp = urlSearch[1].split('&') .map((item) => item.split('=')) .filter((item) => item[0] === 'ref'); referer = temp.length > 0 ? decodeURIComponent(temp[0][1]) : ''; } window.opener.location.href = referer ? (this.options['site_url'] + referer) : this.adminUrl;
const urlSearch = new URL(window.opener.location.href).search.split('?'); let referer = ''; if (urlSearch.length > 1) { const temp = urlSearch[1].split('&') .map((item) => item.split('=')) .filter((item) => item[0] === 'ref'); referer = temp.length > 0 ? decodeURIComponent(temp[0][1]) : ''; } window.opener.location.href = referer ? (this.options['site_url'] + referer) : this.adminUrl;

修改为:

typescriptCopy code
  • 1
window.opener.postMessage({ login: true }, window.origin);
window.opener.postMessage({ login: true }, window.origin);

并在登录页添加message事件监听器:

typescriptCopy code
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
if (this.platform.isBrowser) { window.addEventListener('message', event => { if (event.origin !== window.origin) { return; } if (event.data.login) { window.location.href = this.referer ? (this.options['site_url'] + this.referer) : this.adminUrl; } }, false); }
if (this.platform.isBrowser) { window.addEventListener('message', event => { if (event.origin !== window.origin) { return; } if (event.data.login) { window.location.href = this.referer ? (this.options['site_url'] + this.referer) : this.adminUrl; } }, false); }

注意,别忘了加上this.platform.isBrowser判断。

此方式不仅解决了跨窗口间的通信问题、安全问题,顺带解决了参数的解析问题,可谓一举多得。

完美!