• SpringBoot整合Guacamole教程


    前言

    本文主要介绍的是SpringBoot如何整合Guacamole在浏览器是远程桌面的访问。

    Guacamole 介绍

    Apache Guacamole 是一个无客户端远程桌面网关。它支持标准协议,如 VNC、RDP 和 SSH。我们称之为无客户端,因为不需要插件或客户端软件。
    用户使用他们的网络浏览器连接到 Guacamole 服务器。用 JavaScript 编写的 Guacamole 客户端由 Guacamole 服务器内的网络服务器提供给用户。加载后,此客户端使用 Guacamole 协议通过 HTTP 连接回服务器。部署到 Guacamole 服务器的 Web 应用程序读取 Guacamole 协议并将其转发到 guacd,即原生的 Guacamole 代理。这个代理实际上解释了 Guacamole 协议的内容,代表用户连接到任意数量的远程桌面服务器。Guacamole 协议与 guacd 结合提供了协议不可知性:Guacamole 客户端和 Web 应用程序都不需要知道实际使用的是什么远程桌面协议。

    架构图如下:
    在这里插入图片描述
    协议

    Web 应用程序根本不了解任何远程桌面协议。它不包含对 VNC 或 RDP 或由 Guacamole堆栈支持的任何其他协议的支持。它其实只懂Guacamole协议,这是一个用于远程显示渲染和事件传输的协议。虽然具有这些属性的协议自然具有与远程桌面协议相同的能力,但远程桌面协议和 Guacamole 协议背后的设计原则是不同的:Guacamole 协议并非旨在实现特定桌面环境的功能。
    作为远程显示和交互协议,Guacamole 实现了现有远程桌面协议的超集。因此,向 Guacamole 添加对特定远程桌面协议(如RDP)的支持涉及编写一个中间层,在远程桌面协议和 Guacamole 协议之间进行“转换”。实现这样的转换与实现任何本地客户端没有什么不同,只是这个特定的实现呈现到远程显示器而不是本地显示器。
    处理这种翻译的中间层是 guacd。

    guacd

    guacd 是 Guacamole 的核心,它动态加载对远程桌面协议(称为“客户端插件”)的支持,并根据从 Web 应用程序收到的指令将它们连接到远程桌面。 guacd 是一个守护进程,它与 Guacamole 一起安装并在后台运行,监听来自 Web 应用程序的 TCP 连接。guacd 也不理解任何特定的远程桌面协议,而是实现了足够的 Guacamole 协议来确定需要加载哪些协议支持以及必须将哪些参数传递给它。加载客户端插件后,它会独立于 guacd 运行,并完全控制自身与 Web 应用程序之间的通信,直到客户端插件终止。 guacd 和所有客户端插件都依赖于一个公共库 libguac,这使得通过 Guacamole
    协议进行的通信更容易也更抽象一些。

    网络应用程序

    用户实际与之交互的 Guacamole 部分是 Web 应用程序。
    如前所述,Web 应用程序没有实现任何远程桌面协议。它依赖于 guacd,并且仅实现了一个漂亮的 Web 界面和身份验证层。
    我们选择用 Java 实现 Web 应用程序的服务器端,但没有理由不能用不同的语言编写。事实上,因为 Guacamole 旨在成为一个 API,我们鼓励这样做。

    RealMint

    Guacamole 现在是一个通用的远程桌面网关,但情况并非总是如此。Guacamole最初是用 JavaScript 编写的纯文本 Telnet 客户端,称为 RealMint(“RealMint”是“终端”的字谜)。它主要是为了演示而编写的,虽然目的是有用,但它的主要名声只是因为它是纯 JavaScript。
    RealMint 使用的隧道是用 PHP 编写的。与 Guacamole 的 HTTP 隧道相比,RealMint 的隧道仅使用简单的长轮询,效率低下。RealMint 有一个不错的键盘实现,现在在 Guacamole 的键盘代码的一部分中存在,但这实际上是 RealMint 的功能和可用性的范围。

    鉴于它只是一个遗留协议的实现,并且存在其他几个 JavaScript 终端模拟器,其中大多数已经建立和稳定,该项目被放弃了。

    VNC客户端

    一旦开发人员了解了 HTML5 canvas 标签,并看到它已经在 Firefox 和 Chrome 中实现,就开始在概念验证JavaScript VNC 客户端上开展工作。

    这个客户端是带有 Java 服务器组件的纯 JavaScript,通过将 VNC 转换为相同的基于 XML 的版本来工作。它的发展自然是由VNC 的特性驱动的,它的范围仅限于将单个连接转发给一组用户。尽管相对较慢,但概念验证运行良好,以至于该项目需要一个在线住所,并在SourceForge 上注册为“Guacamole”——一个 HTML5 VNC 客户端。

    随着 Guacamole 的发展并不仅仅是一个概念验证,对速度的需求也增加了,旧的 RealMint 风格的长轮询被放弃了,XML 的使用也是如此。

    由于当时无法信任 WebSocket 得到支持,并且 Java 没有用于 servlet 的 WebSocket 标准,因此开发了一个等效的基于 HTTP 的隧道。如果 WebSocket 因任何原因无法使用,此隧道今天仍在使用。

    远程桌面网关

    开发了一种更快的基于文本的协议,它可以呈现多个远程桌面协议的功能,而不仅仅是 VNC。整个系统被重新构建为一个标准守护进程 guacd 和一个公共库 libguac,后者驱动守护进程和协议支持,并变得可扩展。 该项目的范围从一个足够的 VNC 客户端扩展到一个高性能的 HTML5 远程桌面网关和通用 API。在目前的状态下,Guacamole可以用作中央网关来访问运行不同远程桌面服务器的任意数量的机器。它提供可扩展的身份验证,如果您需要更专业的东西,则可以使用用于基于 HTML5 的远程访问的通用 API。

    官网:http://guacamole.apache.org/

    Guacamole 安装

    参考官网安装: https://guacamole.apache.org/doc/gug/users-guide.html

    建议使用docker安装,可以快速安装,docker安装教程https://www.cnblogs.com/xuwujing/p/15073174.html

    Apache Guacamole分为服务端客户端,均在同一服务器上部署。

    首先是下载镜像,Guacamole数据库可以选择mysql或 PostgreSQL

    docker pull guacamole/guacamole
    docker pull guacamole/guacd
    docker pull mysql/mysql-server
    

    然后初始化mysql以及对mysql进行相关配置。

    docker run --rm guacamole/guacamole /opt/guacamole/bin/initdb.sh --mysql > initdb.sql
    docker run --name mysql --restart=always  -e MYSQL_ROOT_PASSWORD=123456 -d mysql/mysql-server:5.7
    docker cp initdb.sql mysql:/initdb.sql
    sudo  docker exec -it mysql mysql -uroot -p123456
    
    CREATE DATABASE guacamole;
    CREATE USER 'guacamole'@'%' IDENTIFIED BY 'guacamole';
    GRANT SELECT,INSERT,UPDATE,DELETE ON guacamole.* TO 'guacamole'@'%';
    FLUSH PRIVILEGES;
    quit
    docker exec -it mysql bashmysql –uroot –p123456 -Dguacamole<initdb.sql
    

    依次启动:

    docker run --name guacd --restart=always  -d guacamole/guacd
    docker run --name guacamole --restart=always  --link guacd:guacd --link mysql:mysql -e MYSQL_DATABASE='guacamole' -e MYSQL_USER='guacamole' -e MYSQL_PASSWORD='guacamole' -d -p 8080:8080 guacamole/guacamole
    

    在这里插入图片描述

    可以用 docker ps 命令查看是否启动成功!

    启动成功之后,可以在浏览器上面输入:http://ip:8080/guacamole 进行访问,默认的账号密码都是guacadmin;

    在这里插入图片描述

    SpringBoot整合Guacamole

    在整合之前,需要Guacamole已经启动,且准备一台windows的远程机。

    首先是核心pom文件:

    	    <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-websocket</artifactId>
            </dependency>
    
            <!-- Servlet API -->
            <dependency>
                <groupId>javax.servlet</groupId>
                <artifactId>servlet-api</artifactId>
                <version>2.5</version>
                <scope>provided</scope>
            </dependency>
            <!-- Main Guacamole library -->
            <dependency>
                <groupId>org.apache.guacamole</groupId>
                <artifactId>guacamole-common</artifactId>
                <version>1.1.0</version>
            </dependency>
            <!-- Guacamole JavaScript library -->
            <dependency>
                <groupId>org.apache.guacamole</groupId>
                <artifactId>guacamole-common-js</artifactId>
                <version>1.1.0</version>
                <type>zip</type>
                <scope>runtime</scope>
            </dependency>
    

    示例代码可以从这里下载:http://guacamole.apache.org/api-documentation/
    这里我选择的是java和js,这里必须要下载js文件,本篇文章示例在末尾,可以直接下载。

    在这里插入图片描述

    准备好了,编写如下代码,在示例代码有,这里使用的是webSocket,也可以选择http方式建立连接。
    Java代码如下:

     @ServerEndpoint(value = "/webSocket", subprotocols = "guacamole")
    @Component
    public class WebSocketTunnel extends GuacamoleWebSocketTunnelEndpoint {
    
        /**
         * Returns a new tunnel for the given session. How this tunnel is created
         * or retrieved is implementation-dependent.
         *
         * @param session        The session associated with the active WebSocket
         *                       connection.
         * @param endpointConfig information associated with the instance of
         *                       the endpoint created for handling this single connection.
         * @return A connected tunnel, or null if no such tunnel exists.
         * @throws GuacamoleException If an error occurs while retrieving the
         *                            tunnel, or if access to the tunnel is denied.
         */
        @Override
        protected GuacamoleTunnel createTunnel(Session session, EndpointConfig endpointConfig) throws GuacamoleException {
            //guacamole server地址 端口
            String hostname = "192.168.0.1";
            int port = 4822;
            GuacamoleConfiguration configuration = new GuacamoleConfiguration();
            configuration.setProtocol("rdp");
            // 远程windows服务的地址
            configuration.setParameter("hostname", "192.168.0.2");
            configuration.setParameter("port", "3389");
            configuration.setParameter("username", "administrator");
            configuration.setParameter("password", "123456");
            configuration.setParameter("ignore-cert", "true");
    
    
            GuacamoleSocket socket = new ConfiguredGuacamoleSocket(
                    new InetGuacamoleSocket(hostname, port),
                    configuration
            );
    
            GuacamoleTunnel tunnel = new SimpleGuacamoleTunnel(socket);
            return tunnel;
        }
    

    JavaScript代码主要是引用下载的js,使用http的话,核心使用代码就是:

      var guac = new Guacamole.Client(
                    new Guacamole.HTTPTunnel("tunnel")
      );
    

    WebSocket 代码如下:

      var guac = new Guacamole.Client(
                    new Guacamole.WebSocketTunnel("webSocket")
                 );
    

    完整代码如下:

    <!DOCTYPE HTML>
    <!--
        Licensed to the Apache Software Foundation (ASF) under one
        or more contributor license agreements.  See the NOTICE file
        distributed with this work for additional information
        regarding copyright ownership.  The ASF licenses this file
        to you under the Apache License, Version 2.0 (the
        "License"); you may not use this file except in compliance
        with the License.  You may obtain a copy of the License at
    
          http://www.apache.org/licenses/LICENSE-2.0
    
        Unless required by applicable law or agreed to in writing,
        software distributed under the License is distributed on an
        "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
        KIND, either express or implied.  See the License for the
        specific language governing permissions and limitations
        under the License.
    -->
    <html>
    
        <head>
            <link rel="stylesheet" type="text/css" href="guacamole.css"/>
            <title>Guacamole (EXAMPLE)</title>
        </head>
    
        <body>
        <h1>pancm Guacamole</h1>
            <!-- Display -->
            <div id="display"></div>
    
            <!-- Guacamole JavaScript API -->
            <script type="text/javascript"
                src="guacamole-common-js/all.min.js"></script>
    
            <!-- Init -->
            <script type="text/javascript"> /* <![CDATA[ */
    
                // Get display div from document
                var display = document.getElementById("display");
    
                // Instantiate client, using an HTTP tunnel for communications.
               // httl方式
                var guac = new Guacamole.Client(
                    new Guacamole.HTTPTunnel("tunnel")
                );
    		 // WebSocket 方式
                var guac = new Guacamole.Client(
                    new Guacamole.WebSocketTunnel("webSocket")
                 );
    
                // Add client to display div
                display.appendChild(guac.getDisplay().getElement());
    
                // Error handler
                guac.onerror = function(error) {
                    alert(error);
                };
    
                // Connect
                guac.connect();
    
                // Disconnect on close
                window.onunload = function() {
                    guac.disconnect();
                }
    
                // Mouse
                var mouse = new Guacamole.Mouse(guac.getDisplay().getElement());
    
                mouse.onmousedown =
                mouse.onmouseup   =
                mouse.onmousemove = function(mouseState) {
                    guac.sendMouseState(mouseState);
                };
    
                // Keyboard
                var keyboard = new Guacamole.Keyboard(document);
    
                keyboard.onkeydown = function (keysym) {
                    guac.sendKeyEvent(1, keysym);
                };
    
                keyboard.onkeyup = function (keysym) {
                    guac.sendKeyEvent(0, keysym);
                };
    
            /* ]]> */ </script>
    
        </body>
    
    </html>
    

    编写完毕之后,我们启动程序,在浏览器上面输入localhost:9632/api 即可进行远程桌面。

    示例图:
    在这里插入图片描述

    如何进行前后端分离

    前后端在示例代码中是未分离的,如果进行分离的话, 在http或WebSocket请求的前面加上ip和端口即可。
    如下:

      var guac = new Guacamole.Client(
                    new Guacamole.WebSocketTunnel("ws://192.168.0.1:9632/api/webSocket")
                 );
    

    WebSocket方式如何传递参数以及取值

    前端js在请求的url后面加上?key=value&key2=value2& 即可.
    示例如下:

      var guac = new Guacamole.Client(
                    new Guacamole.WebSocketTunnel("ws://192.168.0.1:9632/api/webSocket?ip=192.168.0.1&")
                 );
    

    后端取值代码示例:

    String ip = session.getRequestParameterMap().get("ip").get(0);
    

    如何设置屏幕宽高

    在后端代码中,添加如下配置:

       GuacamoleClientInformation information = new GuacamoleClientInformation();
            information.setOptimalScreenHeight(height);
            information.setOptimalScreenWidth(width);
    
       GuacamoleSocket socket = new ConfiguredGuacamoleSocket(
                    new InetGuacamoleSocket(hostname, port),
                    configuration,
                    information
            );
    

    如何设置录屏

    在后端代码中,添加如下配置:

        String fileName = getNowTime() + ".guac";//文件名
        String outputFilePath = "/home/guacamole";
        //添加会话录制--录屏
        configuration.setParameter("recording-path", outputFilePath);
        configuration.setParameter("create-recording-path", "true");
        configuration.setParameter("recording-name", fileName);
    

    录屏的文件是.guac,我们需要对其进行解码,命令如下:

    guacenc 文件名称
    

    当然也可以对其设置参数配置,示例图如下:

    在这里插入图片描述

    如果对生成的文件格式不满意,想转码的话,可以使用ffmpeg进行转码。

    如何关闭远程桌面

    关闭后端的session即可。代码如下:

      private void optClose(Session session) {
            // 判断当前连接是否还在线
            if (session.isOpen()) {
                try {
                    // 关闭连接
                    CloseReason closeReason = new CloseReason(CloseReason.CloseCodes.NORMAL_CLOSURE, "进行关闭!");
                    session.close(closeReason);
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
    
        }
    

    其他开源远程桌面工具介绍

    Teleport

    Teleport是一款简单易用的堡垒机系统,具有小巧、易用的特点,支持 RDP/SSH/SFTP/Telnet 协议的远程连接和审计管理。

    Teleport由两大部分构成:

    跳板核心服务 WEB操作界面

    安装方式
    下载地址:
    https://www.tp4a.com/download

    Teleport 也是分为服务端和客户端,服务端安装如下,下载好文件之后,上传在linux服务中进行安装,命令如下:

    tar -zxvf teleport-linux-3.0.2.9.tar.gz
    cd teleport-linux-3.0.2.9
    sudo ./setup.sh
    

    相关命令:

    启动: /etc/init.d/teleport start
    停止: /etc/init.d/teleport stop
    重启: /etc/init.d/teleport restart
    查看运行状态: /etc/init.d/teleport status
    

    客户端主要是在进行远程桌面操作和录像回放的时候使用, 安装直接下载到本地运行即可。

    启动之后在浏览器输入:http://teleport服务器IP:7190/ 进行配置即可。

    在这里插入图片描述

    更多请查阅官网!
    官网地址: https://docs.tp4a.com/

    JumpServer

    JumpServer 使用 Python / Django 为主进行开发,遵循 Web 2.0 规范,配备了业界领先的 Web
    Terminal 方案,交互界面美观、用户体验好。

    JumpServer 采纳分布式架构,支持多机房跨区域部署,支持横向扩展,无资产数量及并发限制。

    更多详细了解请查阅官网。
    官网地址:https://www.jumpserver.org/

    在这里插入图片描述

    其他

    项目地址

    项目工程地址:
    https://github.com/xuwujing/springBoot-study/tree/master/springboot-guacamole

    SpringBoot整个集合的地址:
    https://github.com/xuwujing/springBoot-study

    SpringBoot整合系列的文章

    音乐推荐

    原创不易,如果感觉不错,希望给个推荐!您的支持是我写作的最大动力!
    版权声明:
    作者:虚无境
    博客园出处:http://www.cnblogs.com/xuwujing
    CSDN出处:http://blog.csdn.net/qazwsxpcm    
    个人博客出处:http://www.panchengming.com

    如果你对生活感觉到了绝望,请不要气馁。因为这样只会让你更加绝望! 所谓的希望往往都是在绝望中萌发的,所以,请不要放弃希望!
  • 相关阅读:
    day21
    day19
    【淘淘商城项目】jsonp解决ajax跨域问题
    【淘淘商城项目】商品规格参数的表结构设计
    打印日志的时机
    【javascript】call和apply的区别
    MySQL timestamp自动更新时间
    spring管理属性配置文件properties——PropertiesFactoryBean和PropertyPlaceholderConfigurer的区别
    【Maven】修改nexus默认的工作目录
    URIEncoding和UseBodyEncodingForURI的解释
  • 原文地址:https://www.cnblogs.com/xuwujing/p/15096587.html
Copyright © 2020-2023  润新知