前言
本文主要介绍的是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