码迷,mamicode.com
首页 > Web开发 > 详细

如何解决Vue.js里面noVNC的截图问题(2)——蛋疼的cookies验证和node.js的websocket代理

时间:2019-08-16 18:22:40      阅读:496      评论:0      收藏:0      [点我收藏+]

标签:show   问题   点击   ica   mac   padding   页面   submit   isa   

  在上一篇讲noVNC截图功能的文章中,我们利用WebSocket协议的连接不检查跨域的特性解决了noVNC截图失败的问题。

  但是这个方法仅限于没有cookies验证的noVNC服务,但是openstack的noVNC服务,每个虚拟机都要带token,而这个token,是写在cookies里面的。

  看了openstack虚拟桌面的代码,知道里面的代码用token = WebUtil.getQueryVar(‘token‘, null);和WebUtil.createCookie(‘token‘, token, 1)这两句语句获取token再放入cookies,但是把代码放入第1章的Vue代码里面,连接失败。调出F12抓包窗口,发现由于headers关于跨域没设置好,cookies浏览器不认,没有传入服务器。

  解决这个问题的思路是:找一个无视跨域限制,能传cookies的webSocket的客户端,并且对应系统也能开websocket服务端,这个系统作为openstack和主网站的webSocket代理传输数据,Node.js就可以用来解决,刚好整个Vue.js前端项目基于node.js。

技术图片
var WebSocketServer = require(‘websocket‘).server;
var http = require(‘http‘);
var WebSocketClient = require(‘websocket‘).client;

var server1 = http.createServer(function(request, response) {
    console.log((new Date()) + ‘ Server is reseiveing on port 4949‘);
    response.writeHead(204);
    response.end();
});
server1.listen(4949, function() {
    console.log((new Date()) + ‘ Server is listening on port 4949‘);
});

var wsServer = new WebSocketServer({httpServer: server1,autoAcceptConnections: false});

wsServer.on(‘request‘, function(request) {
    var token = request[‘resourceURL‘][‘query‘][‘token‘];
    var ip = request[‘resourceURL‘][‘query‘][‘ip‘];
    var client = new WebSocketClient();
    //模拟noVNC页面连接服务的过程
    client.connect(‘ws://‘ + ip + ‘/websockify‘,‘binary‘,
    ‘http://‘ + ip,{‘Cookie‘:‘token=‘+token});
    client.on(‘connectFailed‘,error=>{console.log(error);});
    //browserConnection就是客户端的webSocket连接
    var browserConnection = request.accept(‘binary‘, request.origin);
    client.on(‘connect‘, function(connection) {
        //connection就是服务端的连接
        connection.on(‘error‘, function(error) {
            console.log("Connection Error: " + error.toString());
            if(browserConnection != null)browserConnection.close();
            browserConnection = null;
        });
        connection.on(‘close‘, function() {
            console.log("Connection Close");
            if(browserConnection != null)browserConnection.close();
            browserConnection = null;
        });
        connection.on(‘message‘, function(message) {
            if (message.type === ‘utf8‘) {
                browserConnection.sendUTF(message.utf8Data);
            }
            else if(message.type === ‘binary‘){
                browserConnection.sendBytes(message.binaryData);
            }
        });
        browserConnection.on(‘message‘, function(message) {
            if (message.type === ‘utf8‘) {
                connection.sendUTF(message.utf8Data);
            }
            else if (message.type === ‘binary‘) {
                connection.sendBytes(message.binaryData);
            }
        });
        browserConnection.on(‘error‘, function(error){
            console.log("BrowserConnection Error: " + error.toString());
            if(connection != null)connection.close();
            connection = null;
        });
        browserConnection.on(‘close‘, function(reasonCode, description){
            console.log("BrowserConnection Close");
            if(connection != null)connection.close();
            connection = null;
        });
    });
});
Node.js websocket代理

  客户端的Vue.js代码

技术图片
<template> 
  <div id="noVNC_all">
  <div id="noVNC_status_bar">
    <div id="noVNC_left_dummy_elem"></div>
    <div id="noVNC_status">Loading</div>
    <div id="noVNC_buttons">
      <input type=button value="Send CtrlAltDel"
             id="sendCtrlAltDelButton" class="noVNC_shown">
      <span id="noVNC_power_buttons" class="noVNC_hidden">
        <input type=button value="Shutdown"
               id="machineShutdownButton">
        <input type=button value="Reboot"
               id="machineRebootButton">
        <input type=button value="Reset"
               id="machineResetButton">
      </span>
    </div>
  </div>
  </div>
</template>

<script>
import * as WebUtil from ./webutil.js;
import RFB from @novnc/novnc/core/rfb.js;
export default {
     components:{
     },
  data() {
    return {
          rfb:null,
          desktopName:null
    };
  },
  methods: {
    connectVNC () {},
    updateDesktopName(e) {
            this.desktopName = e.detail.name;
        },
    credentials(e) {
            var html;

            var form = document.createElement(form);
            form.innerHTML = <label></label>;
            form.innerHTML += <input type=password size=10 id="password_input">;
            form.onsubmit = this.setPassword;

            // bypass status() because it sets text content
            document.getElementById(noVNC_status_bar).setAttribute("class", "noVNC_status_warn");
            document.getElementById(noVNC_status).innerHTML = ‘‘;
            document.getElementById(noVNC_status).appendChild(form);
            document.getElementById(noVNC_status).querySelector(label).textContent = Password Required: ;
        },
    setPassword() {
            this.rfb.sendCredentials({ password: document.getElementById(password_input).value });
            return false;
        },
    sendCtrlAltDel() {
            this.rfb.sendCtrlAltDel();
            return false;
        },
    machineShutdown() {
            this.rfb.machineShutdown();
            return false;
        },
    machineReboot() {
            this.rfb.machineReboot();
            return false;
        },
    machineReset() {
            this.rfb.machineReset();
            return false;
        },
    status(text, level) {
            switch (level) {
                case normal:
                case warn:
                case error:
                    break;
                default:
                    level = "warn";
            }
            document.getElementById(noVNC_status_bar).className = "noVNC_status_" + level;
            document.getElementById(noVNC_status).textContent = text;
        },
    connected(e) {
            document.getElementById(sendCtrlAltDelButton).disabled = false;
            if (WebUtil.getConfigVar(encrypt,
                                     (window.location.protocol === "https:"))) {
                this.status("Connected (encrypted) to " + this.desktopName, "normal");
            } else {
                this.status("Connected (unencrypted) to " + this.desktopName, "normal");
            }
        },
    disconnected(e) {
            document.getElementById(sendCtrlAltDelButton).disabled = true;
            this.updatePowerButtons();
            if (e.detail.clean) {
                this.status("Disconnected", "normal");
            } else {
                this.status("Something went wrong, connection is closed", "error");
            }
        },
    updatePowerButtons() {
            var powerbuttons;
            powerbuttons = document.getElementById(noVNC_power_buttons);
            if (this.rfb.capabilities.power) {
                powerbuttons.className= "noVNC_shown";
            } else {
                powerbuttons.className = "noVNC_hidden";
            }
        }
  },
  mounted() {
        document.getElementById(sendCtrlAltDelButton).onclick = this.sendCtrlAltDel;
        document.getElementById(machineShutdownButton).onclick = this.machineShutdown;
        document.getElementById(machineRebootButton).onclick = this.machineReboot;
        document.getElementById(machineResetButton).onclick = this.machineReset;

        WebUtil.init_logging(WebUtil.getConfigVar(logging, warn));
        document.title = WebUtil.getConfigVar(title, noVNC);
        // By default, use the host and port of server that served this file
        var host = WebUtil.getConfigVar(host, window.location.hostname);
        var port = WebUtil.getConfigVar(port, window.location.port);

        // if port == 80 (or 443) then it won‘t be present and should be
        // set manually
        if (!port) {
            if (window.location.protocol.substring(0,5) == https) {
                port = 443;
            }
            else if (window.location.protocol.substring(0,4) == http) {
                port = 80;
            }
        }
        if(this.$route.params.ipport.indexOf(-) == -1)
            var password = WebUtil.getConfigVar(password, 123456);
        else
            var password = WebUtil.getConfigVar(password, ‘‘);
        var path = WebUtil.getConfigVar(path, websockify);

        // If a token variable is passed in, set the parameter in a cookie.
        // This is used by nova-novncproxy.
        var token = WebUtil.getConfigVar(token, null);
        if (token) {
            // if token is already present in the path we should use it
            path = WebUtil.injectParamIfMissing(path, "token", token);

            WebUtil.createCookie(token, token, 1)
        }
            this.status("Connecting", "normal");

            if ((!host) || (!port)) {
                this.status(Must specify host and port in URL, error);
            }

            var url;

            if (WebUtil.getConfigVar(encrypt,
                                     (window.location.protocol === "https:"))) {
                url = wss;
            } else {
                url = ws;
            }

            if(this.$route.params.ipport == null)
                url += ://192.168.80.61:30926/websockify;
            else if(this.$route.params.ipport.indexOf(-) == -1)//对于符合非openstack链接的ip端口处理
                url += :// + this.$route.params.ipport + /websockify;
            else//对于符合openstack链接的ip端口处理
                url += ://localhost:4949/websockify/websockify?token= + this.$route.params.ipport.split(:-)[1] + &ip= + this.$route.params.ipport.split(:-)[0];

            this.rfb = new RFB(document.querySelector(#noVNC_all), url,
                          { repeaterID: WebUtil.getConfigVar(repeaterID, ‘‘),
                            shared: WebUtil.getConfigVar(shared, true),
                            credentials: { password: password } });
            this.rfb.viewOnly = WebUtil.getConfigVar(view_only, false);
            this.rfb.addEventListener("connect",  this.connected);
            this.rfb.addEventListener("disconnect", this.disconnected);
            this.rfb.addEventListener("capabilities", function () { this.updatePowerButtons(); });
            this.rfb.addEventListener("credentialsrequired", this.credentials);
            this.rfb.addEventListener("desktopname", this.updateDesktopName);
            this.rfb.scaleViewport = WebUtil.getConfigVar(scale, false);
            this.rfb.resizeSession = WebUtil.getConfigVar(resize, false);
  }
};
</script>
<style lang=‘scss‘ scoped>
#noVNC_status_bar {
  width: 100%;
  display:flex;
  justify-content: space-between;
}

#noVNC_status {
  color: #fff;
  font: bold 12px Helvetica;
  margin: auto;
}

.noVNC_status_normal {
  background: linear-gradient(#b2bdcd 0%,#899cb3 49%,#7e93af 51%,#6e84a3 100%);
}

.noVNC_status_error {
  background: linear-gradient(#c83737 0%,#899cb3 49%,#7e93af 51%,#6e84a3 100%);
}

.noVNC_status_warn {
  background: linear-gradient(#b4b41e 0%,#899cb3 49%,#7e93af 51%,#6e84a3 100%);
}

.noNVC_shown {
  display: inline;
}
.noVNC_hidden {
  display: none;
}

#noVNC_left_dummy_elem {
  flex: 1;
}

#noVNC_buttons {
  padding: 1px;
  flex: 1;
  display: flex;
  justify-content: flex-end;
}
</style>
客户端的Vue.js代码

  将node.js代理程序开起来之后,登陆对应页面。再点击截图按钮,可以看到截图成功了,并且之前的cookies跨域问题也没有了。

如何解决Vue.js里面noVNC的截图问题(2)——蛋疼的cookies验证和node.js的websocket代理

标签:show   问题   点击   ica   mac   padding   页面   submit   isa   

原文地址:https://www.cnblogs.com/dgutfly/p/11359434.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!