Search K
Appearance
Appearance
一般的小企业的应用使用单体结构即可满足需求,而大公司需要采用微服务架构来解决高并发,高流量等问题。微前端是随着服务服诞生而出现的一种前端架构思想。即分而治之,先把一个庞大复杂的应用按功能模块分成多个独立模块,每个模块之间互相独立,独立开发,独立部署。还可以把把全部子应用集成部署到一个主应用里面,主应用包含如登录验证,权限等基础模块。本文将介绍前端主应用如何通过 iframe 通信实现,子应用的身份验证等问题。详细的微服务,微前端知识请移步其他文章
在我们项目里面微前端实现方案采用最原始的 iframe 嵌套,微前端应用最大的问题就是主应用和子应用,子应用和子应用之间的消息通信问题了。然而 iframe 提供了通信的 api。
简易代码如下:
父页面(发送消息):
<iframe id="myiframe" src="iframe_message.html"></iframe>
<script>
window.onload = function() {
var iframeWindow = document.getElementById('myiframe').contentWindow;
iframeWindow.postMessage('Hello, I am the parent', '*');
};
</script>
子页面(接收消息):
<script>
window.addEventListener('message', function(event) {
if (event.origin !== window.location.origin) return;
console.log(event.data); // 输出:'Hello, I am the parent'
}, false);
</script>
项目代码如下: 父页面(发送消息):
// fs框架初始化
if (topic === "fsAppMounted") {
const msg = {
topic: "fsAppMounted",
uid: uid,
from: "koca",
body: {
userInfo: {
...userInfo,
orgCode: "999"
},
loginToken: token,
menuArr: newMenuArr,
routeTo
}
};
// console.log(newMenuArr);
// 确保iframe能够收到消息
setTimeout(() => {
targetIframe.postMessage(msg, "*");
localStorage.setItem(routeToKey, "");
}, 1);
// syncDataFn(targetIframe, uid);
}
子页面(接收消息):
eventListen("message").mount((event) => {
if (fsAppMountedResponse.userInfo) {
// console.log('fsAppMountedResponse', fsAppMountedResponse)
const userInfo = fsAppMountedResponse.userInfo;
isRequest = false;
koca.user = userInfo || {};
// 用户信息必要字段F_OP_USER、F_OP_BRANCH、loginName、USER_TICKET_INFO等
koca.user.F_OP_USER = userInfo.userCode || "8888";
koca.user.F_OP_BRANCH = userInfo.orgCode || "";
koca.user.USER_TICKET_INFO = userInfo.token || "";
// koca.user.loginName = userInfo.loginName || ''
koca.user.F_OP_POST = userInfo.post || "8888";
koca.user.CURRENT_POST = userInfo.post || "8888";
koca.user.F_OP_ROLE = userInfo.roleCode || "2";
koca.user.F_CHANNEL = userInfo.channel || "0";
koca.user.F_OP_SITE = userInfo.site || "";
koca.user.F_FUNCTION = userInfo.function || "";
koca.user.F_RUNTIME = userInfo.runtime || "";
setLoginDataSession(JSON.stringify(koca.user));
const loginToken = userInfo.loginToken || fsAppMountedResponse.loginToken;
if (loginToken) {
setLoginTokenSession(loginToken);
}
handleCallback();
}
if (isRequest && koca.user) {
const msg = {
topic: "fsAppMounted",
uid: uid,
from: "fs",
body: {
userInfo: koca.user
}
};
targetIframe.postMessage(msg, "*");
}
return;
});
由上述项目代码可知,子应用等登录 SESSIONID,token 等登录所需要的凭证信息是由主应用通过 iframe 通信传递来的,然后使用 sessionStorage,localStorage 存储 token,使用 cookie 存储 SESSIONID。在以后所有接口请求头的 cookie 会自动携带 SESSIONID,在 axios 请求拦截钩子里面给需要 token 凭证的接口,在请求头里面添加 authorization=token。手动设置 token 的代码如下:
createHttp() {
this._axios = axios.create({ ...requsetBase, timeout: this._conf.timeout })
this._axios.interceptors.request.use(
(config) => {
config = initRequestHeadersAuthorizationInConfig(config)
return config
},
(error) => {
return Promise.reject(error)
}
)
this._axios.interceptors.response.use(
(response) => {
setLoginTokenInResponse(response)
return formatResponse(response, this._conf)
},
(error) => {
return formatError(error, this._conf)
}
)
}
initRequestHeadersAuthorizationInConfig = (config) => {
const { httpData = {}, headers = {} } = config
const { encryptKey = '/session/encryptKey' } = getUrlApi()
const { login = '/auth/login' } = getUrlApi()
const { dynamicKey = '/auth/dynamicKey' } = getUrlApi()
const loginToken = getLoginTokenSession()
// 使用jwt登录验证携带Authorization请求头
if (
httpData.source !== login &&
httpData.source !== encryptKey &&
httpData.source !== dynamicKey &&
loginToken
) {
headers['Authorization'] = `Bearer ${loginToken}`
}
return config
}
如图所示是客户端浏览器存储的 token 和 cookie,端口 3100 是主应用,8080 端口的是子应用
如图所示是接口的请求头信息在了解这几个概念之前我们先知道认证,授权,凭证的概念
一. 认证(Authentication)
二. 授权(Authorization)
三. 凭证(Credentials)
session 是另一种记录服务器和客户端会话状态的机制,session 存储在服务器端,sessionId 会被存储到客户端的 cookie 中
访问资源接口(API)时所需要的资源凭证,服务端无状态化、可扩展性好支持移动端设备,安全,支持跨程序调用,每一次请求都需要携带 token,需要把 token 放到 HTTP 的 Header 里 基于 token 的用户认证是一种服务端无状态的认证方式,服务端不用存放 token 数据。用解析 token 的计算时间换取 session 的存储空间,从而减轻服务器的压力,减少频繁的查询数据库 token 完全由应用管理,所以它可以避开同源策略 session_authorization
sessionStorage 和 localStorage 是浏览器用于缓存数据的 api,有个误区,就是 session 和 sessionStorage 是两个完全不一样的东西,session 是把会话信息存储到服务器,客户端通过响应头的 set-Cookie 来存储 SESSIONID,可以说是 SESSIONID 是客户端和 session 的中介链接者。而 sessionStorage 是客户端用户存储数据的 api
本文主要讨论微前端背景下,如何在主应用处理登录逻辑之后,访问子页面无需再次登录的整体实现流程。首先要知道 iframe 之间跨域通信机制,其后要知道身份验证需要使用哪些技术。关于微前端和身份验证的深层次讨论请移步其他文章