作者 钟来

添加ssh代理服务

  1 +<?xml version="1.0" encoding="UTF-8"?>
  2 +<project xmlns="http://maven.apache.org/POM/4.0.0"
  3 + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4 + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  5 + <modelVersion>4.0.0</modelVersion>
  6 + <parent>
  7 + <groupId>com.zhonglai.luhui</groupId>
  8 + <artifactId>lh-jar</artifactId>
  9 + <version>1.0-SNAPSHOT</version>
  10 + </parent>
  11 +
  12 + <artifactId>lh-jar-ssh-proxy</artifactId>
  13 +
  14 + <properties>
  15 + <maven.compiler.source>8</maven.compiler.source>
  16 + <maven.compiler.target>8</maven.compiler.target>
  17 + <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  18 + </properties>
  19 +
  20 + <dependencies>
  21 + <dependency>
  22 + <groupId>com.jcraft</groupId>
  23 + <artifactId>jsch</artifactId>
  24 + </dependency>
  25 + <dependency>
  26 + <groupId>org.springframework.boot</groupId>
  27 + <artifactId>spring-boot</artifactId>
  28 + </dependency>
  29 +
  30 + </dependencies>
  31 +</project>
  1 +package com.zhonglai.luhui.ssh.proxy;
  2 +
  3 +public class PortForwarding {
  4 + private int localPort;
  5 + private String remoteHost;
  6 + private int remotePort;
  7 +
  8 + // Getters and Setters
  9 + public int getLocalPort() {
  10 + return localPort;
  11 + }
  12 +
  13 + public void setLocalPort(int localPort) {
  14 + this.localPort = localPort;
  15 + }
  16 +
  17 + public String getRemoteHost() {
  18 + return remoteHost;
  19 + }
  20 +
  21 + public void setRemoteHost(String remoteHost) {
  22 + this.remoteHost = remoteHost;
  23 + }
  24 +
  25 + public int getRemotePort() {
  26 + return remotePort;
  27 + }
  28 +
  29 + public void setRemotePort(int remotePort) {
  30 + this.remotePort = remotePort;
  31 + }
  32 +}
  1 +package com.zhonglai.luhui.ssh.proxy;
  2 +
  3 +import com.jcraft.jsch.Channel;
  4 +import com.jcraft.jsch.JSch;
  5 +import com.jcraft.jsch.JSchException;
  6 +import com.jcraft.jsch.Session;
  7 +import org.springframework.beans.factory.annotation.Autowired;
  8 +import org.springframework.scheduling.annotation.Scheduled;
  9 +import org.springframework.stereotype.Component;
  10 +
  11 +import javax.annotation.PostConstruct;
  12 +import javax.annotation.PreDestroy;
  13 +
  14 +@Component
  15 +public class SSHChunnel {
  16 + @Autowired
  17 + private SSHConfig sshConfig;
  18 + private JSch jsch;
  19 + private Session session = null;
  20 + private Channel channel;
  21 +
  22 + /**
  23 + * 创建SSH隧道
  24 + */
  25 + public void createChunnel()
  26 + {
  27 + try {
  28 + jsch = new JSch();
  29 +
  30 + session = jsch.getSession(sshConfig.getUser(),sshConfig.getHost() ,sshConfig.getPort() );
  31 + session.setPassword(sshConfig.getPassword());
  32 + // 设置不进行主机密钥检查
  33 + java.util.Properties config = new java.util.Properties();
  34 + config.put("StrictHostKeyChecking", "no");
  35 + session.setConfig(config);
  36 +
  37 + // 建立SSH连接
  38 + session.connect();
  39 +
  40 + } catch (JSchException e) {
  41 + throw new RuntimeException(e);
  42 + }
  43 +
  44 + }
  45 +
  46 + public void closeChunnel()
  47 + {
  48 + if (channel != null) {
  49 + channel.disconnect();
  50 + }
  51 + if (session != null) {
  52 + session.disconnect();
  53 + }
  54 + }
  55 +
  56 + /**
  57 + * 建立端口转发服务
  58 + */
  59 + public void startChunnel() throws JSchException {
  60 + // 设置端口转发
  61 + if (sshConfig.getPortForwardingList() != null) {
  62 + for (PortForwarding portForwarding : sshConfig.getPortForwardingList()) {
  63 + int assignedLocalPort = session.setPortForwardingL(portForwarding.getLocalPort(), portForwarding.getRemoteHost(), portForwarding.getRemotePort());
  64 + System.out.println("Local port " + assignedLocalPort + " is now forwarding to " + portForwarding.getRemoteHost() + ":" + portForwarding.getRemotePort());
  65 + }
  66 + }
  67 +
  68 + // 保持连接打开
  69 + channel = session.openChannel("shell");
  70 + channel.connect();
  71 + }
  72 +
  73 + /**
  74 + * 在Bean初始化完成后启动SSH隧道
  75 + */
  76 + @PostConstruct
  77 + public void init() {
  78 + if(sshConfig.isEnabled())
  79 + {
  80 + try {
  81 + createChunnel();
  82 + startChunnel();
  83 + } catch (JSchException e) {
  84 + throw new RuntimeException("Failed to start SSH tunnel", e);
  85 + }
  86 + }
  87 +
  88 + }
  89 +
  90 + /**
  91 + * 定期检查SSH连接状态并重连
  92 + */
  93 + @Scheduled(fixedRate = 10000) // 每10秒检查一次
  94 + public void checkAndReconnect() {
  95 + if (sshConfig.isEnabled())
  96 + {
  97 + if (session == null || !session.isConnected()) {
  98 + System.out.println("SSH tunnel is disconnected, attempting to reconnect...");
  99 + try {
  100 + closeChunnel(); // 先关闭旧的连接
  101 + createChunnel();
  102 + startChunnel();
  103 + System.out.println("SSH tunnel reconnected successfully.");
  104 + } catch (JSchException e) {
  105 + System.err.println("Failed to reconnect SSH tunnel: " + e.getMessage());
  106 + }
  107 + }
  108 + }
  109 + }
  110 +
  111 + /**
  112 + * 在Bean销毁前关闭SSH隧道并取消定时任务
  113 + */
  114 + @PreDestroy
  115 + public void destroy() {
  116 + if (session != null && session.isConnected()) {
  117 + closeChunnel();
  118 + System.out.println("SSH tunnel closed on application shutdown.");
  119 + }
  120 + sshConfig.setIsEnabled(false);
  121 + }
  122 +
  123 +}
  1 +package com.zhonglai.luhui.ssh.proxy;
  2 +
  3 +import org.springframework.boot.context.properties.ConfigurationProperties;
  4 +import org.springframework.stereotype.Component;
  5 +
  6 +import java.util.List;
  7 +
  8 +@Component
  9 +@ConfigurationProperties(prefix = "ssh")
  10 +public class SSHConfig {
  11 + private boolean isEnabled ;
  12 + private String user ; //用户名
  13 + private String password ; //密码
  14 + private String host; // 主机地址
  15 + private int port; // 默认SSH端口
  16 + private List<PortForwarding> portForwardingList; // 多个端口转发配置
  17 +
  18 + public boolean isEnabled() {
  19 + return isEnabled;
  20 + }
  21 +
  22 + public void setIsEnabled(boolean isEnabled) {
  23 + this.isEnabled = isEnabled;
  24 + }
  25 +
  26 + public String getUser() {
  27 + return user;
  28 + }
  29 +
  30 + public void setUser(String user) {
  31 + this.user = user;
  32 + }
  33 +
  34 + public String getPassword() {
  35 + return password;
  36 + }
  37 +
  38 + public void setPassword(String password) {
  39 + this.password = password;
  40 + }
  41 +
  42 + public String getHost() {
  43 + return host;
  44 + }
  45 +
  46 + public void setHost(String host) {
  47 + this.host = host;
  48 + }
  49 +
  50 + public int getPort() {
  51 + return port;
  52 + }
  53 +
  54 + public void setPort(int port) {
  55 + this.port = port;
  56 + }
  57 +
  58 + public List<PortForwarding> getPortForwardingList() {
  59 + return portForwardingList;
  60 + }
  61 +
  62 + public void setPortForwardingList(List<PortForwarding> portForwardingList) {
  63 + this.portForwardingList = portForwardingList;
  64 + }
  65 +}
@@ -19,6 +19,7 @@ @@ -19,6 +19,7 @@
19 <module>lh-jar-sys-service</module> 19 <module>lh-jar-sys-service</module>
20 <module>lh-jar-order-service</module> 20 <module>lh-jar-order-service</module>
21 <module>lh-jar-plugins-init</module> 21 <module>lh-jar-plugins-init</module>
  22 + <module>lh-jar-ssh-proxy</module>
22 </modules> 23 </modules>
23 24
24 <properties> 25 <properties>
@@ -54,7 +54,10 @@ @@ -54,7 +54,10 @@
54 <groupId>com.zhonglai.luhui</groupId> 54 <groupId>com.zhonglai.luhui</groupId>
55 <artifactId>lh-jar-order-service</artifactId> 55 <artifactId>lh-jar-order-service</artifactId>
56 </dependency> 56 </dependency>
57 - 57 + <dependency>
  58 + <groupId>com.zhonglai.luhui</groupId>
  59 + <artifactId>lh-jar-ssh-proxy</artifactId>
  60 + </dependency>
58 <!-- 数据库驱动 --> 61 <!-- 数据库驱动 -->
59 <dependency> 62 <dependency>
60 <groupId>mysql</groupId> 63 <groupId>mysql</groupId>
@@ -7,6 +7,7 @@ import org.springframework.context.annotation.ComponentScan; @@ -7,6 +7,7 @@ import org.springframework.context.annotation.ComponentScan;
7 import org.springframework.context.annotation.EnableAspectJAutoProxy; 7 import org.springframework.context.annotation.EnableAspectJAutoProxy;
8 8
9 @ComponentScan(basePackages = { 9 @ComponentScan(basePackages = {
  10 + "com.zhonglai.luhui.ssh.proxy",
10 "com.ruoyi.common", 11 "com.ruoyi.common",
11 "com.ruoyi.system", 12 "com.ruoyi.system",
12 "com.ruoyi.framework", 13 "com.ruoyi.framework",
1 -# 项目相关配置 jhlt: # 名称 name: zhonglai # 版本 version: 3.8.2 # 版权年份 copyrightYear: 2022 # 实例演示开关 demoEnabled: true # 文件路径 示例( Windows配置D:/ruoyi/uploadPath,Linux配置 /home/ruoyi/uploadPath) profile: D:/ruoyi/uploadPath # 获取ip地址开关 addressEnabled: false # 验证码类型 math 数组计算 char 字符验证 captchaType: math # 开发环境配置 server: # 服务器的HTTP端口,默认为8080 port: 18080 servlet: # 应用的访问路径 context-path: / tomcat: # tomcat的URI编码 uri-encoding: UTF-8 # 连接数满后的排队数,默认为100 accept-count: 1000 threads: # tomcat最大线程数,默认为200 max: 800 # Tomcat启动初始化的线程数,默认值10 min-spare: 100 # 日志配置 logging: level: com.ruoyi: debug org.springframework: warn com.zhonglai.luhui: debug # Spring配置 spring: # 资源信息 messages: # 国际化资源文件路径 basename: i18n/messages profiles: active: druid # 文件上传 servlet: multipart: # 单个文件大小 max-file-size: 10MB # 设置总上传的文件大小 max-request-size: 20MB # 服务模块 devtools: restart: # 热部署开关 enabled: true # redis 配置 redis: # 地址 host: 8.129.224.117 # 端口,默认为6379 port: 6379 # 数据库索引 database: 1 # 密码 password: # 连接超时时间 timeout: 10s lettuce: pool: # 连接池中的最小空闲连接 min-idle: 0 # 连接池中的最大空闲连接 max-idle: 8 # 连接池的最大数据库连接数 max-active: 8 # #连接池最大阻塞等待时间(使用负值表示没有限制) max-wait: -1ms # token配置 token: # 令牌自定义标识 header: Authorization # 令牌密钥 secret: abcdefghijklmnopqrstuvwxyz # 令牌有效期(默认30分钟) expireTime: 1440 rediskey: lh-api # MyBatis配置 mybatis: # 搜索指定包别名 typeAliasesPackage: com.ruoyi.**.domain,com.zhonglai.**.domain # 配置mapper的扫描,找到所有的mapper.xml映射文件 mapperLocations: classpath*:mapper/**/*Mapper.xml # 加载全局的配置文件 configLocation: classpath:mybatis/mybatis-config.xml # PageHelper分页插件 pagehelper: helperDialect: mysql supportMethodsArguments: true params: count=countSql # Swagger配置 swagger: # 是否开启swagger enabled: true # 请求前缀 pathMapping: /dev-api # 防止XSS攻击 xss: # 过滤开关 enabled: true # 排除链接(多个用逗号分隔) excludes: /system/notice # 匹配链接 urlPatterns: /system/*,/monitor/*,/tool/* mqtt: client: device_life: 180 sys: ## // 对于登录login 注册register 验证码captchaImage 允许匿名访问 antMatchers: /login/ApiLogin/*,/content/**,/test/**,/fish/FishPriceCollection/*,/iot/IotTerminal/listByDeviceId/* # NameServer地址 rocketmq: name-server: 47.115.144.179:9876 # 默认的消息组 producer: group: deviceCommand send-message-timeout: 30000 send-topic: lh-mqtt-service-deviceCommand-test send-tags: 1  
  1 +# 项目相关配置 jhlt: # 名称 name: zhonglai # 版本 version: 3.8.2 # 版权年份 copyrightYear: 2022 # 实例演示开关 demoEnabled: true # 文件路径 示例( Windows配置D:/ruoyi/uploadPath,Linux配置 /home/ruoyi/uploadPath) profile: D:/ruoyi/uploadPath # 获取ip地址开关 addressEnabled: false # 验证码类型 math 数组计算 char 字符验证 captchaType: math # 开发环境配置 server: # 服务器的HTTP端口,默认为8080 port: 18080 servlet: # 应用的访问路径 context-path: / tomcat: # tomcat的URI编码 uri-encoding: UTF-8 # 连接数满后的排队数,默认为100 accept-count: 1000 threads: # tomcat最大线程数,默认为200 max: 800 # Tomcat启动初始化的线程数,默认值10 min-spare: 100 # 日志配置 logging: level: com.ruoyi: debug org.springframework: warn com.zhonglai.luhui: debug # Spring配置 spring: # 资源信息 messages: # 国际化资源文件路径 basename: i18n/messages profiles: active: druid # 文件上传 servlet: multipart: # 单个文件大小 max-file-size: 10MB # 设置总上传的文件大小 max-request-size: 20MB # 服务模块 devtools: restart: # 热部署开关 enabled: true # redis 配置 redis: # 地址 host: localhost # 端口,默认为6379 port: 6379 # 数据库索引 database: 1 # 密码 password: # 连接超时时间 timeout: 10s lettuce: pool: # 连接池中的最小空闲连接 min-idle: 0 # 连接池中的最大空闲连接 max-idle: 8 # 连接池的最大数据库连接数 max-active: 8 # #连接池最大阻塞等待时间(使用负值表示没有限制) max-wait: -1ms # token配置 token: # 令牌自定义标识 header: Authorization # 令牌密钥 secret: abcdefghijklmnopqrstuvwxyz # 令牌有效期(默认30分钟) expireTime: 1440 rediskey: lh-api # MyBatis配置 mybatis: # 搜索指定包别名 typeAliasesPackage: com.ruoyi.**.domain,com.zhonglai.**.domain # 配置mapper的扫描,找到所有的mapper.xml映射文件 mapperLocations: classpath*:mapper/**/*Mapper.xml # 加载全局的配置文件 configLocation: classpath:mybatis/mybatis-config.xml # PageHelper分页插件 pagehelper: helperDialect: mysql supportMethodsArguments: true params: count=countSql # Swagger配置 swagger: # 是否开启swagger enabled: true # 请求前缀 pathMapping: /dev-api # 防止XSS攻击 xss: # 过滤开关 enabled: true # 排除链接(多个用逗号分隔) excludes: /system/notice # 匹配链接 urlPatterns: /system/*,/monitor/*,/tool/* mqtt: client: device_life: 180 sys: ## // 对于登录login 注册register 验证码captchaImage 允许匿名访问 antMatchers: /login/ApiLogin/*,/content/**,/test/**,/fish/FishPriceCollection/*,/iot/IotTerminal/listByDeviceId/* # NameServer地址 rocketmq: name-server: 8.129.224.117:9876 # 默认的消息组 producer: group: deviceCommand send-message-timeout: 30000 send-topic: lh-mqtt-service-deviceCommand-test send-tags: 1 ssh: isEnabled: true host: 119.23.218.181 port: 22 user: root password: Luhui586 portForwardingList: - localPort: 6379 remotePort: 6379 remoteHost: 127.0.0.1 - localPort: 3306 remotePort: 3306 remoteHost: 127.0.0.1
@@ -379,6 +379,12 @@ @@ -379,6 +379,12 @@
379 <artifactId>lh-jar-plugins-init</artifactId> 379 <artifactId>lh-jar-plugins-init</artifactId>
380 <version>${ruoyi.version}</version> 380 <version>${ruoyi.version}</version>
381 </dependency> 381 </dependency>
  382 + <!-- ssh代理 -->
  383 + <dependency>
  384 + <groupId>com.zhonglai.luhui</groupId>
  385 + <artifactId>lh-jar-ssh-proxy</artifactId>
  386 + <version>${ruoyi.version}</version>
  387 + </dependency>
382 <!-- 支持data --> 388 <!-- 支持data -->
383 <dependency> 389 <dependency>
384 <groupId>org.projectlombok</groupId> 390 <groupId>org.projectlombok</groupId>