当前位置:   article > 正文

javaweb集成guacamole在html页面中展示_guacamole-common-js

guacamole-common-js

上一篇幅是介绍guacamole的安装,接下来说说使用

项目需求,需要在页面中集成远程桌面,要去掉基础认证。整体的方案有两种,都在这里说一下吧。

一、不需要guacamole客户端,在自己项目中实现socket通道。与页面进行连接(建议使用第二种)

1、环境准备

启动guacd服务

service guacd start

2、在自己的java项目中引入guacamole-common的包,版本与自己的guacd版本一致。

  1. <dependency>
  2. <groupId>org.apache.guacamole</groupId>
  3. <artifactId>guacamole-common</artifactId>
  4. <version>1.0.0</version>
  5. </dependency>

3、自定义servlet实现GuacamoleHTTPTunnelServlet,官方截图如下

引入jar,之后创建MyGuacamoleHTTPTunnelServlet

  1. package com.xx.guacalome;
  2. import org.apache.guacamole.GuacamoleException;
  3. import org.apache.guacamole.net.GuacamoleTunnel;
  4. import org.apache.guacamole.net.InetGuacamoleSocket;
  5. import org.apache.guacamole.net.SimpleGuacamoleTunnel;
  6. import org.apache.guacamole.protocol.ConfiguredGuacamoleSocket;
  7. import org.apache.guacamole.protocol.GuacamoleConfiguration;
  8. import org.apache.guacamole.servlet.GuacamoleHTTPTunnelServlet;
  9. import org.springframework.beans.factory.annotation.Value;
  10. import javax.servlet.annotation.WebServlet;
  11. import javax.servlet.http.HttpServletRequest;
  12. /**
  13. * @description:
  14. * @Author: huangsan
  15. * @Date: 2020/5/27 11:01 上午
  16. */
  17. @WebServlet(urlPatterns = "/tunnel")
  18. public class MyGuacamoleHTTPTunnelServlet extends GuacamoleHTTPTunnelServlet {
  19. @Value("${guacamole.guacd.host}")
  20. private String guacdHost;
  21. @Value("${guacamole.guacd.port}")
  22. private String guacdPort;
  23. @Value("${guacamole.target.protocol}")
  24. private String targetProtocol;
  25. @Value("${guacamole.target.host}")
  26. private String targetHost;
  27. @Value("${guacamole.target.port}")
  28. private String targetPort;
  29. @Value("${guacamole.target.username}")
  30. private String targetUsername;
  31. @Value("${guacamole.target.password}")
  32. private String targetPassword;
  33. @Override
  34. protected GuacamoleTunnel doConnect(HttpServletRequest httpServletRequest) throws GuacamoleException {
  35. System.out.println("-----------远程桌面调用成功");
  36. GuacamoleConfiguration config = new GuacamoleConfiguration();
  37. config.setProtocol(targetProtocol);
  38. config.setParameter("hostname", targetHost);
  39. config.setParameter("port", targetPort);
  40. config.setParameter("username", targetUsername);
  41. config.setParameter("password", targetPassword);
  42. return new SimpleGuacamoleTunnel(
  43. new ConfiguredGuacamoleSocket(new InetGuacamoleSocket(this.guacdHost, Integer.parseInt(this.guacdPort)), config));
  44. }
  45. }

在yml配置文件中配置我们需要的value

  1. guacamole:
  2. guacd:
  3. host: 10.0.30.50
  4. port: 4822
  5. target:
  6. protocol: rdp
  7. host: 10.0.30.224
  8. port: 3389
  9. username: admin
  10. password: 123456

启动类上配置@ServletComponentScan注解扫描servlet

启动项目即可,我们后台的通道就搭建完成

4、配置guacamole-common-js

创建前端html页面,在页面中定义展示区域的div。<div id="display"></div>

all.min.js获取的方法,在maven中依赖

  1. <dependency>
  2. <groupId>org.apache.guacamole</groupId>
  3. <artifactId>guacamole-common-js</artifactId>
  4. <version>1.0.0</version>
  5. </dependency>

然后去maven仓库中找到这个包,解压之后就可以找到相关jar。

  1. <%@ page language="java" contentType="text/html; charset=UTF-8"
  2. pageEncoding="UTF-8" %>
  3. <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
  4. <!DOCTYPE html>
  5. <html>
  6. <head>
  7. <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
  8. <title>Guacamole show</title>
  9. </head>
  10. <body>
  11. <script type="text/javascript"
  12. src="${pageContext.request.contextPath }/static/js/bigData/deviceMonitor/all.min.js"></script>
  13. <div id="display"></div>
  14. <script type="text/javascript">
  15. let display = document.getElementById("display");
  16. let guac = new Guacamole.Client(
  17. new Guacamole.HTTPTunnel("http://localhost/tunnel")
  18. // new Guacamole.WebSocketTunnel('ws://localhost/websocket-tunnel'),
  19. );
  20. display.appendChild(guac.getDisplay().getElement());
  21. guac.connect();
  22. window.onunload = function () {
  23. guac.disconnect();
  24. }
  25. //下面是鼠标键盘是否支持
  26. let mouse = new Guacamole.Mouse(guac.getDisplay().getElement());
  27. mouse.onmousedown =
  28. mouse.onmouseup =
  29. mouse.onmousemove = function (mouseState) {
  30. guac.sendMouseState(mouseState);
  31. };
  32. let keyboard = new Guacamole.Keyboard(document);
  33. keyboard.onkeydown = function (keysym) {
  34. guac.sendKeyEvent(1, keysym);
  35. };
  36. keyboard.onkeyup = function (keysym) {
  37. guac.sendKeyEvent(0, keysym);
  38. };
  39. </script>
  40. </body>
  41. </html>

guacamole client支持httptunnel或者websockettunnel 这里我们就配置一个httptunnel。

通道地址指向我们项目中暴露的servlet地址即可。

以上内容在guacamole的API中说的很详细,在页面中还支持展示更多内容,具体请参考html与js如下:

http://guacamole.apache.org/doc/gug/guacamole-common-js.html

http://guacamole.apache.org/doc/1.0.0/guacamole-common-js/

二、依赖于guacamole的客户端和服务端来搞事情(以上的方法,需要在自己的项目中去引入其他的依赖,还不如利用其客户端当为服务一样使用)

1、环境准备

需要启动guacd的客户端和服务端,一个tomcat一个是service guacd start,就不赘述了。

2、与上面前端服务一样,创建html,指定展示区域div

3、编写js,如下(到这里就直接可以使用了,参数按照我这个来拼接就可以了,456节就是对这些参数的分析,如果是直接用的话就不用看下去了,当然想知道是什么的可以继续看下

  1. guac.onerror = function (error) {
  2. alert(error);
  3. };
  4. $.ajax({
  5. type: "POST",
  6. async: false,
  7. url: "http://10.0.30.50:8888/g/api/tokens",
  8. data: "username=hhb&password=hhb123",
  9. }).done(function (result) {
  10. guac.connect("token=" + result.authToken + '&GUAC_DATA_SOURCE=default&GUAC_ID=test1&GUAC_TYPE=c&GUAC_WIDTH=900');
  11. }).fail(function (result) {
  12. console.error("token error: ", result.status, result.statusText)
  13. });
  14. window.onunload = function () {
  15. guac.disconnect();
  16. }
  17. // Mouse 鼠标事件
  18. let mouse = new Guacamole.Mouse(guac.getDisplay().getElement());
  19. mouse.onmousedown =
  20. mouse.onmouseup =
  21. mouse.onmousemove = function(mouseState) {
  22. guac.sendMouseState(mouseState);
  23. };
  24. // Keyboard 键盘事件
  25. let keyboard = new Guacamole.Keyboard(document);
  26. keyboard.onkeydown = function (keysym) {
  27. guac.sendKeyEvent(1, keysym);
  28. };
  29. keyboard.onkeyup = function (keysym) {
  30. guac.sendKeyEvent(0, keysym);
  31. };

4、讲解一下js内容,首先要解决认证的问题

官网的描述是可以在connect中传递任意数据,那么我们将获取的的token等信息就可以在connect的时候进行传递。

那就先来获取token,我们看客户端登陆是如何获取token的,之后用ajax来模拟一个

ajax代码如上所示。

token拿到之后我们要封装到connect中去,这里我在api中是没有看到任何说明指出connect怎么来拼接,没办法了反正是开源的,down一下代码来读一读吧

下载github上代码

拿到代码就好办了我们来看一下。

5、在源码中找到我们想要的

---我们如果自己创建的话是创建一个tunnel的servlet,所以我们全局搜索“/tunnel”。

---在TunnelModule类中我么看到了configureServlets方法,从这里我们看出有两种方式一种http一种websocket

  1. @Override
  2. protected void configureServlets() {
  3. bind(TunnelRequestService.class);
  4. // Set up HTTP tunnel
  5. serve("/tunnel").with(RestrictedGuacamoleHTTPTunnelServlet.class);
  6. // Try to load each WebSocket tunnel in sequence
  7. for (String classname : WEBSOCKET_MODULES) {
  8. if (loadWebSocketModule(classname)) {
  9. logger.debug("WebSocket module loaded: {}", classname);
  10. return;
  11. }
  12. }
  13. // Warn of lack of WebSocket
  14. logger.info("WebSocket support NOT present. Only HTTP will be used.");
  15. }

---进入http的创建中我们看到

  1. @Singleton
  2. public class RestrictedGuacamoleHTTPTunnelServlet extends GuacamoleHTTPTunnelServlet {
  3. /**
  4. * Service for handling tunnel requests.
  5. */
  6. @Inject
  7. private TunnelRequestService tunnelRequestService;
  8. /**
  9. * Logger for this class.
  10. */
  11. private static final Logger logger = LoggerFactory.getLogger(RestrictedGuacamoleHTTPTunnelServlet.class);
  12. @Override
  13. protected GuacamoleTunnel doConnect(HttpServletRequest request) throws GuacamoleException {
  14. // Attempt to create HTTP tunnel
  15. GuacamoleTunnel tunnel = tunnelRequestService.createTunnel(new HTTPTunnelRequest(request));
  16. // If successful, warn of lack of WebSocket
  17. logger.info("Using HTTP tunnel (not WebSocket). Performance may be sub-optimal.");
  18. return tunnel;
  19. }
  20. }

发现了一个和我们之前的实现思路一样的继承GuacamoleHTTPTunnelServlet

---我们看到对HTTPTunnelRequest进行了封装参数是我么的HttpServletRequest

---点进去发现其实就是把我们的httpservlet的参数拿出来而已

  1. public HTTPTunnelRequest(HttpServletRequest request) {
  2. // For each parameter
  3. for (Map.Entry<String, String[]> mapEntry : ((Map<String, String[]>)
  4. request.getParameterMap()).entrySet()) {
  5. // Get parameter name and corresponding values
  6. String parameterName = mapEntry.getKey();
  7. List<String> parameterValues = Arrays.asList(mapEntry.getValue());
  8. // Store copy of all values in our own map
  9. parameterMap.put(
  10. parameterName,
  11. new ArrayList<String>(parameterValues)
  12. );
  13. }
  14. }

---看来我们只要把参数给http请求就可以了,那我们再来看看都需要哪些参数点到tunnelRequestService.createTunnel方法中

  1. public GuacamoleTunnel createTunnel(TunnelRequest request)
  2. throws GuacamoleException {
  3. // Parse request parameters
  4. String authToken = request.getAuthenticationToken();
  5. String id = request.getIdentifier();
  6. TunnelRequest.Type type = request.getType();
  7. String authProviderIdentifier = request.getAuthenticationProviderIdentifier();
  8. GuacamoleClientInformation info = getClientInformation(request);
  9. GuacamoleSession session = authenticationService.getGuacamoleSession(authToken);
  10. UserContext userContext = session.getUserContext(authProviderIdentifier);
  11. try {
  12. // Create connected tunnel using provided connection ID and client information
  13. GuacamoleTunnel tunnel = createConnectedTunnel(userContext, type, id, info);
  14. // Notify listeners to allow connection to be vetoed
  15. fireTunnelConnectEvent(session.getAuthenticatedUser(),
  16. session.getAuthenticatedUser().getCredentials(), tunnel);
  17. // Associate tunnel with session
  18. return createAssociatedTunnel(tunnel, authToken, session, userContext, type, id);
  19. }
  20. // Ensure any associated session is invalidated if unauthorized
  21. catch (GuacamoleUnauthorizedException e) {
  22. // If there is an associated auth token, invalidate it
  23. if (authenticationService.destroyGuacamoleSession(authToken))
  24. logger.debug("Implicitly invalidated session for token \"{}\".", authToken);
  25. // Continue with exception processing
  26. throw e;
  27. }
  28. }

---重点来看

String authToken                = request.getAuthenticationToken();
String id                       = request.getIdentifier();
TunnelRequest.Type type         = request.getType();
String authProviderIdentifier   = request.getAuthenticationProviderIdentifier();
GuacamoleClientInformation info = getClientInformation(request);

首先前四个request的方法我们可以点进去看看,无非就是获取参数,但是id\type\authProviderIdentifier这三个参数都是必须的

  1. public String getAuthenticationProviderIdentifier()
  2. throws GuacamoleException {
  3. return getRequiredParameter(AUTH_PROVIDER_IDENTIFIER_PARAMETER);
  4. }

---既然知道了参数的key,那我们就可以在前端来模拟了,具体都有哪些参数可以参考

  1. /*
  2. * Licensed to the Apache Software Foundation (ASF) under one
  3. * or more contributor license agreements. See the NOTICE file
  4. * distributed with this work for additional information
  5. * regarding copyright ownership. The ASF licenses this file
  6. * to you under the Apache License, Version 2.0 (the
  7. * "License"); you may not use this file except in compliance
  8. * with the License. You may obtain a copy of the License at
  9. *
  10. * http://www.apache.org/licenses/LICENSE-2.0
  11. *
  12. * Unless required by applicable law or agreed to in writing,
  13. * software distributed under the License is distributed on an
  14. * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
  15. * KIND, either express or implied. See the License for the
  16. * specific language governing permissions and limitations
  17. * under the License.
  18. */
  19. package org.apache.guacamole.tunnel;
  20. import java.util.List;
  21. import org.apache.guacamole.GuacamoleClientException;
  22. import org.apache.guacamole.GuacamoleClientException;
  23. import org.apache.guacamole.GuacamoleException;
  24. import org.apache.guacamole.GuacamoleException;
  25. /**
  26. * A request object which provides only the functions absolutely required to
  27. * retrieve and connect to a tunnel.
  28. */
  29. public abstract class TunnelRequest {
  30. /**
  31. * The name of the request parameter containing the user's authentication
  32. * token.
  33. */
  34. public static final String AUTH_TOKEN_PARAMETER = "token";
  35. /**
  36. * The name of the parameter containing the identifier of the
  37. * AuthenticationProvider associated with the UserContext containing the
  38. * object to which a tunnel is being requested.
  39. */
  40. public static final String AUTH_PROVIDER_IDENTIFIER_PARAMETER = "GUAC_DATA_SOURCE";
  41. /**
  42. * The name of the parameter specifying the type of object to which a
  43. * tunnel is being requested. Currently, this may be "c" for a Guacamole
  44. * connection, or "g" for a Guacamole connection group.
  45. */
  46. public static final String TYPE_PARAMETER = "GUAC_TYPE";
  47. /**
  48. * The name of the parameter containing the unique identifier of the object
  49. * to which a tunnel is being requested.
  50. */
  51. public static final String IDENTIFIER_PARAMETER = "GUAC_ID";
  52. /**
  53. * The name of the parameter containing the desired display width, in
  54. * pixels.
  55. */
  56. public static final String WIDTH_PARAMETER = "GUAC_WIDTH";
  57. /**
  58. * The name of the parameter containing the desired display height, in
  59. * pixels.
  60. */
  61. public static final String HEIGHT_PARAMETER = "GUAC_HEIGHT";
  62. /**
  63. * The name of the parameter containing the desired display resolution, in
  64. * DPI.
  65. */
  66. public static final String DPI_PARAMETER = "GUAC_DPI";
  67. /**
  68. * The name of the parameter specifying one supported audio mimetype. This
  69. * will normally appear multiple times within a single tunnel request -
  70. * once for each mimetype.
  71. */
  72. public static final String AUDIO_PARAMETER = "GUAC_AUDIO";
  73. /**
  74. * The name of the parameter specifying one supported video mimetype. This
  75. * will normally appear multiple times within a single tunnel request -
  76. * once for each mimetype.
  77. */
  78. public static final String VIDEO_PARAMETER = "GUAC_VIDEO";
  79. /**
  80. * The name of the parameter specifying one supported image mimetype. This
  81. * will normally appear multiple times within a single tunnel request -
  82. * once for each mimetype.
  83. */
  84. public static final String IMAGE_PARAMETER = "GUAC_IMAGE";
  85. /**
  86. * All supported object types that can be used as the destination of a
  87. * tunnel.
  88. */
  89. public static enum Type {
  90. /**
  91. * A Guacamole connection.
  92. */
  93. CONNECTION("c"),
  94. /**
  95. * A Guacamole connection group.
  96. */
  97. CONNECTION_GROUP("g");
  98. /**
  99. * The parameter value which denotes a destination object of this type.
  100. */
  101. final String PARAMETER_VALUE;
  102. /**
  103. * Defines a Type having the given corresponding parameter value.
  104. *
  105. * @param value
  106. * The parameter value which denotes a destination object of this
  107. * type.
  108. */
  109. Type(String value) {
  110. PARAMETER_VALUE = value;
  111. }
  112. };
  113. //下面没用的都删掉了
  114. }

那我们来分析一下我们需要传的参数

"token=" + result.authToken + '&GUAC_DATA_SOURCE=default&GUAC_ID=test1&GUAC_TYPE=c&GUAC_WIDTH=900'

---token:不用说,为什么不是必须的参数,参考api的快速连接部分。

---GUAC_DATA_SOURCE:在获取token的时候就传递回来了,我这里是default

{"authToken":"x","username":"hhb","dataSource":"default","availableDataSources":["quickconnect","default"]}

---GUAC_ID:就是我们user-mapping中的connect的name

---GUAC_TYPE:看源码发现是个枚举类型,这里我们没引入组的概念(1.1.0版本有),这里直接传c

  1. public static enum Type {
  2. /**
  3. * A Guacamole connection.
  4. */
  5. CONNECTION("c"),
  6. /**
  7. * A Guacamole connection group.
  8. */
  9. CONNECTION_GROUP("g");
  10. /**
  11. * The parameter value which denotes a destination object of this type.
  12. */
  13. final String PARAMETER_VALUE;
  14. /**
  15. * Defines a Type having the given corresponding parameter value.
  16. *
  17. * @param value
  18. * The parameter value which denotes a destination object of this
  19. * type.
  20. */
  21. Type(String value) {
  22. PARAMETER_VALUE = value;
  23. }
  24. };

---GUAC_WIDTH:这属于随便的参数了,看个人需要我就指定了个宽度,你们可以自由继续拼装。

5、我们知道了connect中需要传递的一些参数,那就直接拼接出来即可,直接调用创建隧道。

6、总结:这种方法好处就是不用自己在项目中引入guacamole的内容了,不好的地方是我们需要解决跨域问题,虽然guacamole是个tomcat,但是我无论怎么配置跨域都没解决,没办法最后使用nginx来解决了。

以上就是web集成guacamole的两种方式了,其实思路就是一种,创建隧道与guacamole-common-js连接就可以了,有什么问题欢迎大家指出。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/知新_RL/article/detail/550727
推荐阅读
相关标签
  

闽ICP备14008679号