1.背景:多个vue前端项目需要组合成一个大系统,期间包括主系统向子系统间的跳转以及传值,尤其是需要把用户信息或者用户token传过去,如下图:

2.问题 :使用window.open()和window.location.href跳转时,新页面的地址栏会显示参数,如下:

http://127.0.0.1:8071/?t="dddddasdasdasda"。 
这样会暴露参数内容,用户可以修改地址栏的参数。如果提交的参数修改可能会出现业务上的错误,甚至可以跳过权限验证,实现本来没有的权限。

3. 尝试解决方向

1).给用户参数加密 让别人看不到参数值 比如说用js的加密解密方法 escape()和unescape() 把用户名和密码组合成一个对象或者字符串当参数传过去

   这样虽然参数值加密了,但是这个带参数的地址是正确的,只要这个地址被人正确的打开过,之后就可以用这个地址打开,直接进后台管理页面,这样是及其危险的,别人都不需要解密获取你真实的值,可能现在3岁的小孩子都可以复制粘贴了,所以这个方法也是不可取的,必须把这个参数隐藏掉,或者最好整个跳转地址都不需要显示出来

2)按照1)的思路我们决定把参数隐藏

使用过的方法包括用post提交和组装成form的方式传参数并跳转,然而失败了,压根跳不出本系统的登录拦截,简单代码展示如下:

(1)通过构建form表单,将参数写入表单中,并提交,代码如下:

(function(){
    //设置命名空间
    var CodeSTD = window.CodeSTD || {};

    window.CodeSTD = CodeSTD; 

    /**
     * 创建Form表单,在页面跳转时,隐藏路径中的参数信息
     * @author shaohsuai
     * @param config Object
     *  <p>url:form的Action,提交的后台地址</p>
     *  <p>method:使用POST还是GET提交表单</p>
     *  <p>params:参数 K-V</p>
     * @return Form
     */
    CodeSTD.form = function(config){
        config = config || {};
        var url = config.url,
            method = config.method || 'GET',
            params = config.params || {};


        var form = document.createElement('form');
        form.action = url;
        form.method = method;
        form.target = "_blank";


        for(var param in params){
            var value = params[param],
                input = document.createElement('input');
            input.type = 'hidden';
            input.name = param;
            input.value = value;
            form.appendChild(input);
        }
        return form;
    }

})()

function f_status(id){
//window.open("${ctx}/sbgl/sbgl!getHostStautsInfo?hostid="+id);
var form = new CodeSTD.form({
        url:'${ctx}/sbgl/sbgl!getHostStautsInfo',
        method:'POST',
        params:{
            hostid:id,
        }
    })
    $(form).submit();
    form = null;
}

(2)通过使用Post方式将参数提交,主要思想代码如下:

//发送POST请求跳转到指定页面
function httpPost(URL, PARAMS) {
    var temp = document.createElement("form");
    temp.action = URL;
    temp.method = "post";
    temp.style.display = "none";

    for (var x in PARAMS) {
        var opt = document.createElement("textarea");
        opt.name = x;
        opt.value = PARAMS[x];
        temp.appendChild(opt);
    }

    document.body.appendChild(temp);
    temp.submit();

    return temp;
}

3)尝试方案3,将用户信息放到 window.localStorage 或者共享cookie里面保存,然后其他项目在登录的时候判断是否存在对象,存在就直接跳转打开项目,不用再在子系统里面再次登录了

但是这样有bug,(1)window.localStorage子系统间不共享 ,只在每个系统内部使用

                       (2)在用户不知道的情况下将数据存到cookie里面, 跳过登录这种方法也是极不安全的,只要用户打开系统页面就不用登录,即使我们在主系统内部对cookie进行严格的把控,cookie也可以解决这种夸子域问题 ,但还是不可取,太危险了

4.最终解决方法:使用 postMessage window.addEventListener 主系统派发用户 信息 子系统接收主系统信息获取用户参数,从而在访问子系统的时候获取到主系统用户信息从而跳过登录

有关PostMessage的demo示例如下,公司代码就不贴在这里了,涉及机密,请大家谅解,有需要可以再下方留言,也加我公众号给我留言,我看到会回复大家

outter.html 主页面

<!DOCTYPE html> 
<html lang="zh-cn">
 <head> 
 <meta charset="UTF-8"> 
 <title>outter</title>
 </head> 
 <body> 获取的信息为: 
 <div id="getMessage"></div> 
 <iframe src="http://192.168.0.214:8088/test/inner.html" frameborder="1" ></iframe> 
 <hr> 要传入内部的信息:
 <input type="text" id="out">
 <input type="button" value="点击" id="but"> 
 <script>
 var message=document.getElementById("getMessage");
 var text=document.getElementById("out");
 window.addEventListener("message",function(e){ 
 if(e.data!=null){ message.innerText=e.data; } 
 }); 
 document.getElementById("but").onclick=function(){
 window.frames[0].postMessage(text.value,"http://192.168.0.214:8088"); 
 text.value=""; 
 } 
 </script> 
 </body>
 </html>

inner.html 子页面

<!DOCTYPE html> <html lang="zh-cn"> 
<head> 
<meta charset="UTF-8"> 
<title>inner</title> 
</head> 
<body> 
外面传进来的信息为: 
<div id="getMessage"></div> 
<hr> 要传到外面的信息为:
<input type="text" id="text">
<input type="button" value="传递" id="but"> 
<script> 
var message=document.getElementById("getMessage"); 
var text=document.getElementById("text");
 document.getElementById("but").onclick=function(){
 window.parent.postMessage(text.value,"http://192.168.0.214:8088"); 
 text.value=""; 
 } 
 window.addEventListener("message",function(e){ 
 if(e.data!=null){ message.innerText=e.data; }
 }); 
 </script> 
 </body> 
 </html>

这个示例包括主系统和子系统间的相互传值,最具代表性,给大家贴在这里

启动方法:

       将分别新建outter.html和inner.html页面,将内容复制进去,把ip和端口改成自己的ip和电脑的tomcat的端口

再tomcat webapp目录下新建一个test文件夹,随便什么名字也可以,我这里叫test,然后将那2个html放进去,启动tomcat即可

如图:

启动后就可以看到主页面和子页面的传值示例,很简单

5.更多:有关更多的PostMessage的使用方法可以查看网址:postMessage

6.踩坑点:

关于postmessage取不到值得问题

是因为当主页面发送信息的时候子页面还没有生成,无法接受参数,可以再主页面加载完成后使用一个点击事件来驱动重新发送一遍数据,这样就可以了,或者使用定时器来解决


将不定期更新资源,欢迎持续关注

想获得更多的学习知识请关注微信公众号:西北码农或扫下方二维码

  

 

 

Logo

前往低代码交流专区

更多推荐