作者 钟来

添加ssh代理服务

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.zhonglai.luhui</groupId>
<artifactId>lh-jar</artifactId>
<version>1.0-SNAPSHOT</version>
</parent>
<artifactId>lh-jar-ssh-proxy</artifactId>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>com.jcraft</groupId>
<artifactId>jsch</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot</artifactId>
</dependency>
</dependencies>
</project>
\ No newline at end of file
... ...
package com.zhonglai.luhui.ssh.proxy;
public class PortForwarding {
private int localPort;
private String remoteHost;
private int remotePort;
// Getters and Setters
public int getLocalPort() {
return localPort;
}
public void setLocalPort(int localPort) {
this.localPort = localPort;
}
public String getRemoteHost() {
return remoteHost;
}
public void setRemoteHost(String remoteHost) {
this.remoteHost = remoteHost;
}
public int getRemotePort() {
return remotePort;
}
public void setRemotePort(int remotePort) {
this.remotePort = remotePort;
}
}
... ...
package com.zhonglai.luhui.ssh.proxy;
import com.jcraft.jsch.Channel;
import com.jcraft.jsch.JSch;
import com.jcraft.jsch.JSchException;
import com.jcraft.jsch.Session;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
@Component
public class SSHChunnel {
@Autowired
private SSHConfig sshConfig;
private JSch jsch;
private Session session = null;
private Channel channel;
/**
* 创建SSH隧道
*/
public void createChunnel()
{
try {
jsch = new JSch();
session = jsch.getSession(sshConfig.getUser(),sshConfig.getHost() ,sshConfig.getPort() );
session.setPassword(sshConfig.getPassword());
// 设置不进行主机密钥检查
java.util.Properties config = new java.util.Properties();
config.put("StrictHostKeyChecking", "no");
session.setConfig(config);
// 建立SSH连接
session.connect();
} catch (JSchException e) {
throw new RuntimeException(e);
}
}
public void closeChunnel()
{
if (channel != null) {
channel.disconnect();
}
if (session != null) {
session.disconnect();
}
}
/**
* 建立端口转发服务
*/
public void startChunnel() throws JSchException {
// 设置端口转发
if (sshConfig.getPortForwardingList() != null) {
for (PortForwarding portForwarding : sshConfig.getPortForwardingList()) {
int assignedLocalPort = session.setPortForwardingL(portForwarding.getLocalPort(), portForwarding.getRemoteHost(), portForwarding.getRemotePort());
System.out.println("Local port " + assignedLocalPort + " is now forwarding to " + portForwarding.getRemoteHost() + ":" + portForwarding.getRemotePort());
}
}
// 保持连接打开
channel = session.openChannel("shell");
channel.connect();
}
/**
* 在Bean初始化完成后启动SSH隧道
*/
@PostConstruct
public void init() {
if(sshConfig.isEnabled())
{
try {
createChunnel();
startChunnel();
} catch (JSchException e) {
throw new RuntimeException("Failed to start SSH tunnel", e);
}
}
}
/**
* 定期检查SSH连接状态并重连
*/
@Scheduled(fixedRate = 10000) // 每10秒检查一次
public void checkAndReconnect() {
if (sshConfig.isEnabled())
{
if (session == null || !session.isConnected()) {
System.out.println("SSH tunnel is disconnected, attempting to reconnect...");
try {
closeChunnel(); // 先关闭旧的连接
createChunnel();
startChunnel();
System.out.println("SSH tunnel reconnected successfully.");
} catch (JSchException e) {
System.err.println("Failed to reconnect SSH tunnel: " + e.getMessage());
}
}
}
}
/**
* 在Bean销毁前关闭SSH隧道并取消定时任务
*/
@PreDestroy
public void destroy() {
if (session != null && session.isConnected()) {
closeChunnel();
System.out.println("SSH tunnel closed on application shutdown.");
}
sshConfig.setIsEnabled(false);
}
}
... ...
package com.zhonglai.luhui.ssh.proxy;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
import java.util.List;
@Component
@ConfigurationProperties(prefix = "ssh")
public class SSHConfig {
private boolean isEnabled ;
private String user ; //用户名
private String password ; //密码
private String host; // 主机地址
private int port; // 默认SSH端口
private List<PortForwarding> portForwardingList; // 多个端口转发配置
public boolean isEnabled() {
return isEnabled;
}
public void setIsEnabled(boolean isEnabled) {
this.isEnabled = isEnabled;
}
public String getUser() {
return user;
}
public void setUser(String user) {
this.user = user;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getHost() {
return host;
}
public void setHost(String host) {
this.host = host;
}
public int getPort() {
return port;
}
public void setPort(int port) {
this.port = port;
}
public List<PortForwarding> getPortForwardingList() {
return portForwardingList;
}
public void setPortForwardingList(List<PortForwarding> portForwardingList) {
this.portForwardingList = portForwardingList;
}
}
... ...
... ... @@ -19,6 +19,7 @@
<module>lh-jar-sys-service</module>
<module>lh-jar-order-service</module>
<module>lh-jar-plugins-init</module>
<module>lh-jar-ssh-proxy</module>
</modules>
<properties>
... ...
... ... @@ -54,7 +54,10 @@
<groupId>com.zhonglai.luhui</groupId>
<artifactId>lh-jar-order-service</artifactId>
</dependency>
<dependency>
<groupId>com.zhonglai.luhui</groupId>
<artifactId>lh-jar-ssh-proxy</artifactId>
</dependency>
<!-- 数据库驱动 -->
<dependency>
<groupId>mysql</groupId>
... ...
... ... @@ -7,6 +7,7 @@ import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
@ComponentScan(basePackages = {
"com.zhonglai.luhui.ssh.proxy",
"com.ruoyi.common",
"com.ruoyi.system",
"com.ruoyi.framework",
... ...
# 项目相关配置 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
\ No newline at end of file
# 项目相关配置 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
\ No newline at end of file
... ...
... ... @@ -379,6 +379,12 @@
<artifactId>lh-jar-plugins-init</artifactId>
<version>${ruoyi.version}</version>
</dependency>
<!-- ssh代理 -->
<dependency>
<groupId>com.zhonglai.luhui</groupId>
<artifactId>lh-jar-ssh-proxy</artifactId>
<version>${ruoyi.version}</version>
</dependency>
<!-- 支持data -->
<dependency>
<groupId>org.projectlombok</groupId>
... ...