重温一下第三方登录流程:
- 访问登录页;
- 点击第三方登录,跳到对应的第三方登录页;
- 授权登录后,原登录页刷新、跳转到登录后的成功页(来源页,or,后台管理页);
- 关闭打开的第三方登录后的回调页,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
方式,这应该就是处理此问题的最佳方案了。
原来的跳转代码:
- 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;
修改为:
- 1
window.opener.postMessage({ login: true }, window.origin);
并在登录页添加message
事件监听器:
- 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);
}
注意,别忘了加上this.platform.isBrowser
判断。
此方式不仅解决了跨窗口间的通信问题、安全问题,顺带解决了参数的解析问题,可谓一举多得。
完美!