项目背景
- 公司各个小系统,小站点实在是有点多,每次都要输账号密码。有点不方便,于是搞起了单点登录
系统构成
- 单点登录管理后台,用于配置单点系统用户(内部用户)关联哪些子站点的用户(外部用户)
- 前台页面。用于给内部用户登录,登录后,可以查看配置的站点,点击跳转,可以直接登录
- 两个系统都使用vue搭建
管理后台
前端页面
- 该版本为生产版本,下面版本上线后体验差。故优化
- 核心代码使用url拼接参数+进行路由拦截形式,因为postmessage方式,在接收的时候,一般都是在路由初始化后,所以无法做到合理的拦截。使用url方式,可拦截ticket
该版本存在异步问题。所以优化成上面的版本
- 情景1
用户先到单点系统,输入账号密码登录(内部用户),登录成功后(后端会给我们一个ticket,存在本地),可以拿到后台配置的子站点信息, 点击要登录的系统,核心功能点(我们将拿到的ticket。通过iframe和postMessage的方式,跨域给到子站点,子系统进行监听后写入localStroage中),跳转到子站点,这时候能拿到ticket,去调接口,成功后,重写子系统的token。登录成功。
- 情景2
用户先到子系统,这时候子系统发现,ticket为空或者过期,且token为空或者过期,跳转到单点系统,单点系统如果是登录状态,同情景1,给跳转过来的子系统写ticket。两个情景不同点,判断document.referre。
- 难点,用跨域写数据的方式,可能存在异步问题。例如,我们写过去的时候,页面跳转过去,这时候还未写成功,子系统判断ticket为空,又回到单点。如此反复。出现bug,解决 =》 在子系统使用延时器的方式去拿ticket、可能有点low,但是暂时解决了自己的问题。
核心代码,子系统监听message
window.addEventListener(
"message",
function (event) {
if (!!event.data.ticket) {
localStorage.setItem("ticket", event.data.ticket);
localStorage.setItem("url", event.data.url);
}
},
false
);
单点系统给子系统写入ticket
var ticket = localStorage.getItem("token");
var iframe = document.createElement("iframe");
iframe.src = url;
iframe.setAttribute(
"style",
"position:absolute;width:0px;height:0px;left:-500px;top:-500px;"
);
document.body.append(iframe);
iframe.onload = () => {
iframe.contentWindow.postMessage(
{
ticket,
url,
},
url
);
setTimeout(function () {
iframe.remove();
}, 5000);
setTimeout(function () {
window.open(url, "_self");
}, 1000);
大致流程如上,各个子系统和单点间的跳转,存在问题,例如在无痕模式下,写入ticket会被清除。初版刚上,后期需要测试优化。仅做记录 that's all