赞
踩
上一篇幅是介绍guacamole的安装,接下来说说使用
项目需求,需要在页面中集成远程桌面,要去掉基础认证。整体的方案有两种,都在这里说一下吧。
一、不需要guacamole客户端,在自己项目中实现socket通道。与页面进行连接(建议使用第二种)
1、环境准备
启动guacd服务
service guacd start
2、在自己的java项目中引入guacamole-common的包,版本与自己的guacd版本一致。
- <dependency>
- <groupId>org.apache.guacamole</groupId>
- <artifactId>guacamole-common</artifactId>
- <version>1.0.0</version>
- </dependency>
3、自定义servlet实现GuacamoleHTTPTunnelServlet,官方截图如下
引入jar,之后创建MyGuacamoleHTTPTunnelServlet
- package com.xx.guacalome;
-
- import org.apache.guacamole.GuacamoleException;
- import org.apache.guacamole.net.GuacamoleTunnel;
- import org.apache.guacamole.net.InetGuacamoleSocket;
- import org.apache.guacamole.net.SimpleGuacamoleTunnel;
- import org.apache.guacamole.protocol.ConfiguredGuacamoleSocket;
- import org.apache.guacamole.protocol.GuacamoleConfiguration;
- import org.apache.guacamole.servlet.GuacamoleHTTPTunnelServlet;
- import org.springframework.beans.factory.annotation.Value;
-
- import javax.servlet.annotation.WebServlet;
- import javax.servlet.http.HttpServletRequest;
-
- /**
- * @description:
- * @Author: huangsan
- * @Date: 2020/5/27 11:01 上午
- */
- @WebServlet(urlPatterns = "/tunnel")
- public class MyGuacamoleHTTPTunnelServlet extends GuacamoleHTTPTunnelServlet {
-
- @Value("${guacamole.guacd.host}")
- private String guacdHost;
- @Value("${guacamole.guacd.port}")
- private String guacdPort;
- @Value("${guacamole.target.protocol}")
- private String targetProtocol;
- @Value("${guacamole.target.host}")
- private String targetHost;
- @Value("${guacamole.target.port}")
- private String targetPort;
- @Value("${guacamole.target.username}")
- private String targetUsername;
- @Value("${guacamole.target.password}")
- private String targetPassword;
-
-
- @Override
- protected GuacamoleTunnel doConnect(HttpServletRequest httpServletRequest) throws GuacamoleException {
- System.out.println("-----------远程桌面调用成功");
- GuacamoleConfiguration config = new GuacamoleConfiguration();
- config.setProtocol(targetProtocol);
- config.setParameter("hostname", targetHost);
- config.setParameter("port", targetPort);
- config.setParameter("username", targetUsername);
- config.setParameter("password", targetPassword);
- return new SimpleGuacamoleTunnel(
- new ConfiguredGuacamoleSocket(new InetGuacamoleSocket(this.guacdHost, Integer.parseInt(this.guacdPort)), config));
-
- }
- }
在yml配置文件中配置我们需要的value
- guacamole:
- guacd:
- host: 10.0.30.50
- port: 4822
- target:
- protocol: rdp
- host: 10.0.30.224
- port: 3389
- username: admin
- password: 123456
启动类上配置@ServletComponentScan注解扫描servlet
启动项目即可,我们后台的通道就搭建完成
4、配置guacamole-common-js
创建前端html页面,在页面中定义展示区域的div。<div id="display"></div>
all.min.js获取的方法,在maven中依赖
- <dependency>
- <groupId>org.apache.guacamole</groupId>
- <artifactId>guacamole-common-js</artifactId>
- <version>1.0.0</version>
- </dependency>
然后去maven仓库中找到这个包,解压之后就可以找到相关jar。
- <%@ page language="java" contentType="text/html; charset=UTF-8"
- pageEncoding="UTF-8" %>
- <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
- <!DOCTYPE html>
- <html>
- <head>
- <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
- <title>Guacamole show</title>
- </head>
- <body>
- <script type="text/javascript"
- src="${pageContext.request.contextPath }/static/js/bigData/deviceMonitor/all.min.js"></script>
- <div id="display"></div>
- <script type="text/javascript">
- let display = document.getElementById("display");
- let guac = new Guacamole.Client(
- new Guacamole.HTTPTunnel("http://localhost/tunnel")
- // new Guacamole.WebSocketTunnel('ws://localhost/websocket-tunnel'),
- );
- display.appendChild(guac.getDisplay().getElement());
- guac.connect();
- window.onunload = function () {
- guac.disconnect();
- }
- //下面是鼠标键盘是否支持
- let mouse = new Guacamole.Mouse(guac.getDisplay().getElement());
- mouse.onmousedown =
- mouse.onmouseup =
- mouse.onmousemove = function (mouseState) {
- guac.sendMouseState(mouseState);
- };
- let keyboard = new Guacamole.Keyboard(document);
- keyboard.onkeydown = function (keysym) {
- guac.sendKeyEvent(1, keysym);
- };
- keyboard.onkeyup = function (keysym) {
- guac.sendKeyEvent(0, keysym);
- };
- </script>
- </body>
- </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节就是对这些参数的分析,如果是直接用的话就不用看下去了,当然想知道是什么的可以继续看下)
- guac.onerror = function (error) {
- alert(error);
- };
- $.ajax({
- type: "POST",
- async: false,
- url: "http://10.0.30.50:8888/g/api/tokens",
- data: "username=hhb&password=hhb123",
- }).done(function (result) {
- guac.connect("token=" + result.authToken + '&GUAC_DATA_SOURCE=default&GUAC_ID=test1&GUAC_TYPE=c&GUAC_WIDTH=900');
- }).fail(function (result) {
- console.error("token error: ", result.status, result.statusText)
- });
- window.onunload = function () {
- guac.disconnect();
- }
- // Mouse 鼠标事件
- let mouse = new Guacamole.Mouse(guac.getDisplay().getElement());
- mouse.onmousedown =
- mouse.onmouseup =
- mouse.onmousemove = function(mouseState) {
- guac.sendMouseState(mouseState);
- };
- // Keyboard 键盘事件
- let keyboard = new Guacamole.Keyboard(document);
- keyboard.onkeydown = function (keysym) {
- guac.sendKeyEvent(1, keysym);
- };
- keyboard.onkeyup = function (keysym) {
- guac.sendKeyEvent(0, keysym);
- };
4、讲解一下js内容,首先要解决认证的问题
官网的描述是可以在connect中传递任意数据,那么我们将获取的的token等信息就可以在connect的时候进行传递。
那就先来获取token,我们看客户端登陆是如何获取token的,之后用ajax来模拟一个
ajax代码如上所示。
token拿到之后我们要封装到connect中去,这里我在api中是没有看到任何说明指出connect怎么来拼接,没办法了反正是开源的,down一下代码来读一读吧
下载github上代码
拿到代码就好办了我们来看一下。
5、在源码中找到我们想要的
---我们如果自己创建的话是创建一个tunnel的servlet,所以我们全局搜索“/tunnel”。
---在TunnelModule类中我么看到了configureServlets方法,从这里我们看出有两种方式一种http一种websocket
-
- @Override
- protected void configureServlets() {
-
- bind(TunnelRequestService.class);
-
- // Set up HTTP tunnel
- serve("/tunnel").with(RestrictedGuacamoleHTTPTunnelServlet.class);
-
- // Try to load each WebSocket tunnel in sequence
- for (String classname : WEBSOCKET_MODULES) {
- if (loadWebSocketModule(classname)) {
- logger.debug("WebSocket module loaded: {}", classname);
- return;
- }
- }
-
- // Warn of lack of WebSocket
- logger.info("WebSocket support NOT present. Only HTTP will be used.");
-
- }
---进入http的创建中我们看到
- @Singleton
- public class RestrictedGuacamoleHTTPTunnelServlet extends GuacamoleHTTPTunnelServlet {
-
- /**
- * Service for handling tunnel requests.
- */
- @Inject
- private TunnelRequestService tunnelRequestService;
-
- /**
- * Logger for this class.
- */
- private static final Logger logger = LoggerFactory.getLogger(RestrictedGuacamoleHTTPTunnelServlet.class);
-
- @Override
- protected GuacamoleTunnel doConnect(HttpServletRequest request) throws GuacamoleException {
-
- // Attempt to create HTTP tunnel
- GuacamoleTunnel tunnel = tunnelRequestService.createTunnel(new HTTPTunnelRequest(request));
-
- // If successful, warn of lack of WebSocket
- logger.info("Using HTTP tunnel (not WebSocket). Performance may be sub-optimal.");
-
- return tunnel;
-
- }
-
- }
发现了一个和我们之前的实现思路一样的继承GuacamoleHTTPTunnelServlet
---我们看到对HTTPTunnelRequest进行了封装参数是我么的HttpServletRequest
---点进去发现其实就是把我们的httpservlet的参数拿出来而已
- public HTTPTunnelRequest(HttpServletRequest request) {
-
- // For each parameter
- for (Map.Entry<String, String[]> mapEntry : ((Map<String, String[]>)
- request.getParameterMap()).entrySet()) {
-
- // Get parameter name and corresponding values
- String parameterName = mapEntry.getKey();
- List<String> parameterValues = Arrays.asList(mapEntry.getValue());
-
- // Store copy of all values in our own map
- parameterMap.put(
- parameterName,
- new ArrayList<String>(parameterValues)
- );
-
- }
-
- }
---看来我们只要把参数给http请求就可以了,那我们再来看看都需要哪些参数点到tunnelRequestService.createTunnel方法中
- public GuacamoleTunnel createTunnel(TunnelRequest request)
- throws GuacamoleException {
-
- // Parse request parameters
- String authToken = request.getAuthenticationToken();
- String id = request.getIdentifier();
- TunnelRequest.Type type = request.getType();
- String authProviderIdentifier = request.getAuthenticationProviderIdentifier();
- GuacamoleClientInformation info = getClientInformation(request);
-
- GuacamoleSession session = authenticationService.getGuacamoleSession(authToken);
- UserContext userContext = session.getUserContext(authProviderIdentifier);
-
- try {
-
- // Create connected tunnel using provided connection ID and client information
- GuacamoleTunnel tunnel = createConnectedTunnel(userContext, type, id, info);
-
- // Notify listeners to allow connection to be vetoed
- fireTunnelConnectEvent(session.getAuthenticatedUser(),
- session.getAuthenticatedUser().getCredentials(), tunnel);
-
- // Associate tunnel with session
- return createAssociatedTunnel(tunnel, authToken, session, userContext, type, id);
-
- }
-
- // Ensure any associated session is invalidated if unauthorized
- catch (GuacamoleUnauthorizedException e) {
-
- // If there is an associated auth token, invalidate it
- if (authenticationService.destroyGuacamoleSession(authToken))
- logger.debug("Implicitly invalidated session for token \"{}\".", authToken);
-
- // Continue with exception processing
- throw e;
-
- }
-
- }
---重点来看
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这三个参数都是必须的
- public String getAuthenticationProviderIdentifier()
- throws GuacamoleException {
- return getRequiredParameter(AUTH_PROVIDER_IDENTIFIER_PARAMETER);
- }
---既然知道了参数的key,那我们就可以在前端来模拟了,具体都有哪些参数可以参考
- /*
- * 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.
- */
-
- package org.apache.guacamole.tunnel;
-
- import java.util.List;
- import org.apache.guacamole.GuacamoleClientException;
- import org.apache.guacamole.GuacamoleClientException;
- import org.apache.guacamole.GuacamoleException;
- import org.apache.guacamole.GuacamoleException;
-
- /**
- * A request object which provides only the functions absolutely required to
- * retrieve and connect to a tunnel.
- */
- public abstract class TunnelRequest {
-
- /**
- * The name of the request parameter containing the user's authentication
- * token.
- */
- public static final String AUTH_TOKEN_PARAMETER = "token";
-
- /**
- * The name of the parameter containing the identifier of the
- * AuthenticationProvider associated with the UserContext containing the
- * object to which a tunnel is being requested.
- */
- public static final String AUTH_PROVIDER_IDENTIFIER_PARAMETER = "GUAC_DATA_SOURCE";
-
- /**
- * The name of the parameter specifying the type of object to which a
- * tunnel is being requested. Currently, this may be "c" for a Guacamole
- * connection, or "g" for a Guacamole connection group.
- */
- public static final String TYPE_PARAMETER = "GUAC_TYPE";
-
- /**
- * The name of the parameter containing the unique identifier of the object
- * to which a tunnel is being requested.
- */
- public static final String IDENTIFIER_PARAMETER = "GUAC_ID";
-
- /**
- * The name of the parameter containing the desired display width, in
- * pixels.
- */
- public static final String WIDTH_PARAMETER = "GUAC_WIDTH";
-
- /**
- * The name of the parameter containing the desired display height, in
- * pixels.
- */
- public static final String HEIGHT_PARAMETER = "GUAC_HEIGHT";
-
- /**
- * The name of the parameter containing the desired display resolution, in
- * DPI.
- */
- public static final String DPI_PARAMETER = "GUAC_DPI";
-
- /**
- * The name of the parameter specifying one supported audio mimetype. This
- * will normally appear multiple times within a single tunnel request -
- * once for each mimetype.
- */
- public static final String AUDIO_PARAMETER = "GUAC_AUDIO";
-
- /**
- * The name of the parameter specifying one supported video mimetype. This
- * will normally appear multiple times within a single tunnel request -
- * once for each mimetype.
- */
- public static final String VIDEO_PARAMETER = "GUAC_VIDEO";
-
- /**
- * The name of the parameter specifying one supported image mimetype. This
- * will normally appear multiple times within a single tunnel request -
- * once for each mimetype.
- */
- public static final String IMAGE_PARAMETER = "GUAC_IMAGE";
-
- /**
- * All supported object types that can be used as the destination of a
- * tunnel.
- */
- public static enum Type {
-
- /**
- * A Guacamole connection.
- */
- CONNECTION("c"),
-
- /**
- * A Guacamole connection group.
- */
- CONNECTION_GROUP("g");
-
- /**
- * The parameter value which denotes a destination object of this type.
- */
- final String PARAMETER_VALUE;
-
- /**
- * Defines a Type having the given corresponding parameter value.
- *
- * @param value
- * The parameter value which denotes a destination object of this
- * type.
- */
- Type(String value) {
- PARAMETER_VALUE = value;
- }
-
- };
-
- //下面没用的都删掉了
- }
那我们来分析一下我们需要传的参数
"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
- public static enum Type {
-
- /**
- * A Guacamole connection.
- */
- CONNECTION("c"),
-
- /**
- * A Guacamole connection group.
- */
- CONNECTION_GROUP("g");
-
- /**
- * The parameter value which denotes a destination object of this type.
- */
- final String PARAMETER_VALUE;
-
- /**
- * Defines a Type having the given corresponding parameter value.
- *
- * @param value
- * The parameter value which denotes a destination object of this
- * type.
- */
- Type(String value) {
- PARAMETER_VALUE = value;
- }
-
- };
---GUAC_WIDTH:这属于随便的参数了,看个人需要我就指定了个宽度,你们可以自由继续拼装。
5、我们知道了connect中需要传递的一些参数,那就直接拼接出来即可,直接调用创建隧道。
6、总结:这种方法好处就是不用自己在项目中引入guacamole的内容了,不好的地方是我们需要解决跨域问题,虽然guacamole是个tomcat,但是我无论怎么配置跨域都没解决,没办法最后使用nginx来解决了。
以上就是web集成guacamole的两种方式了,其实思路就是一种,创建隧道与guacamole-common-js连接就可以了,有什么问题欢迎大家指出。
赞
踩
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。