From 2a2910ac73e5f02d9374dbb3a38b813158cb6967 Mon Sep 17 00:00:00 2001
From: zhangmeng <1334717033@qq.com>
Date: Sat, 11 Mar 2023 17:54:01 +0800
Subject: [PATCH] =?UTF-8?q?=E6=B7=BB=E5=8A=A0ssh=20=E6=9C=8D=E5=8A=A1=2020?=
=?UTF-8?q?23=E5=B9=B43=E6=9C=8811=E6=97=A517:53:50?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
pom.xml | 13 +
.../tools/controller/HomeController.java | 4 +
.../controller/SSHConnectionController.java | 124 +++++++++
.../controller/ServerToolsController.java | 29 +-
.../com/zhangmeng/tools/ssh/SSHService.java | 16 ++
.../zhangmeng/tools/ssh/SSHServiceImpl.java | 248 ++++++++++++++++++
.../zhangmeng/tools/utils/ResourcesUtils.java | 1 +
src/main/resources/fxml/home.fxml | 1 +
src/main/resources/fxml/ssh-connection.fxml | 25 ++
9 files changed, 458 insertions(+), 3 deletions(-)
create mode 100644 src/main/java/com/zhangmeng/tools/controller/SSHConnectionController.java
create mode 100644 src/main/java/com/zhangmeng/tools/ssh/SSHService.java
create mode 100644 src/main/java/com/zhangmeng/tools/ssh/SSHServiceImpl.java
create mode 100644 src/main/resources/fxml/ssh-connection.fxml
diff --git a/pom.xml b/pom.xml
index 885624a..de1e5e2 100644
--- a/pom.xml
+++ b/pom.xml
@@ -282,6 +282,19 @@
ftpserver-core
1.1.1
+
+
+ commons-net
+ commons-net
+ 3.6
+
+
+
+ com.jcraft
+ jsch
+ 0.1.54
+
+
diff --git a/src/main/java/com/zhangmeng/tools/controller/HomeController.java b/src/main/java/com/zhangmeng/tools/controller/HomeController.java
index ebfab01..f3c2c25 100644
--- a/src/main/java/com/zhangmeng/tools/controller/HomeController.java
+++ b/src/main/java/com/zhangmeng/tools/controller/HomeController.java
@@ -463,4 +463,8 @@ public class HomeController implements Serializable {
ListView listView = (ListView) fx.lookup("#listView");
listView.getSelectionModel().select(index);
}
+
+ public void ssh_client_menu_item(ActionEvent event) {
+ load_server_tools(2);
+ }
}
\ No newline at end of file
diff --git a/src/main/java/com/zhangmeng/tools/controller/SSHConnectionController.java b/src/main/java/com/zhangmeng/tools/controller/SSHConnectionController.java
new file mode 100644
index 0000000..7873dab
--- /dev/null
+++ b/src/main/java/com/zhangmeng/tools/controller/SSHConnectionController.java
@@ -0,0 +1,124 @@
+package com.zhangmeng.tools.controller;
+
+import com.zhangmeng.tools.ssh.SSHService;
+import com.zhangmeng.tools.ssh.SSHServiceImpl;
+import com.zhangmeng.tools.utils.AlertUtils;
+import javafx.application.Platform;
+import javafx.beans.property.SimpleObjectProperty;
+import javafx.beans.value.ChangeListener;
+import javafx.beans.value.ObservableValue;
+import javafx.collections.ListChangeListener;
+import javafx.collections.ObservableList;
+import javafx.fxml.FXML;
+import javafx.scene.control.Button;
+import javafx.scene.control.TextArea;
+import javafx.scene.control.TextField;
+import lombok.extern.slf4j.Slf4j;
+
+/**
+ * @author : 芊芊墨客
+ * @version : 1.0
+ * @date : 2023-03-11 17:10
+ */
+@Slf4j
+public class SSHConnectionController {
+
+ @FXML
+ public Button connection;
+
+ @FXML
+ public TextArea show_result;
+
+ @FXML
+ public TextField command;
+
+ @FXML
+ private TextField username;
+
+ @FXML
+ private TextField password;
+
+ @FXML
+ private TextField host;
+
+ @FXML
+ private TextField port;
+
+ private SSHService sshService = null;
+
+ private SimpleObjectProperty uuid = new SimpleObjectProperty<>("2023311");
+ private SimpleObjectProperty status = new SimpleObjectProperty<>(0);
+
+ @FXML
+ public void initialize() {
+
+ sshService = new SSHServiceImpl();
+
+ connection.setOnAction(event -> {
+ if (username.getText().length() == 0 ){
+ AlertUtils.alert_warning("用户名不能为空!");
+ return;
+ }
+
+ if (password.getText().length() == 0 ){
+ AlertUtils.alert_warning("密码不能为空!");
+ return;
+ }
+
+ if (host.getText().length() == 0 ){
+ AlertUtils.alert_warning("服务地址不能为空!");
+ return;
+ }
+
+ if (port.getText().length() == 0 ){
+ AlertUtils.alert_warning("服务端口不能为空!");
+ return;
+ }
+ SSHServiceImpl.SSHConnectInfo sshConnectInfo = new SSHServiceImpl.SSHConnectInfo();
+ sshConnectInfo.setUsername(username.getText());
+ sshConnectInfo.setPassword(password.getText());
+ sshConnectInfo.setHost(host.getText());
+ sshConnectInfo.setPort(Integer.parseInt(port.getText()));
+
+ //init
+ this.sshService.initConnection(uuid.get(),sshConnectInfo);
+
+ //connection
+ this.sshService.recvHandle("", SSHServiceImpl.Type.connect,uuid.get());
+
+ AlertUtils.alert_msg("连额成功!");
+ status.set(1);
+ });
+
+ command.setOnAction(event -> {
+ if (status.getValue() != 1){
+ AlertUtils.alert_warning("请连接后再试!");
+ return;
+ }
+ if (command.getText().length() == 0 ){
+ AlertUtils.alert_warning("请输入命令后再试!");
+ return;
+ }
+ this.sshService.recvHandle(command.getText(),SSHServiceImpl.Type.command, uuid.get());
+ });
+ ObservableList message_list = SSHServiceImpl.message_list;
+ message_list.addListener((ListChangeListener) c -> {
+ while (c.next()) {
+ if (c.wasAdded()) {
+ StringBuilder stringBuilder = new StringBuilder();
+ for (String s : message_list) {
+ stringBuilder.append(s);
+ }
+ receive(stringBuilder.toString());
+ }
+ }
+ });
+
+ }
+
+ public void receive(String msg){
+ Platform.runLater(() -> {
+ this.show_result.setText(msg);
+ });
+ }
+}
diff --git a/src/main/java/com/zhangmeng/tools/controller/ServerToolsController.java b/src/main/java/com/zhangmeng/tools/controller/ServerToolsController.java
index e409e5e..9e73920 100644
--- a/src/main/java/com/zhangmeng/tools/controller/ServerToolsController.java
+++ b/src/main/java/com/zhangmeng/tools/controller/ServerToolsController.java
@@ -40,6 +40,7 @@ public class ServerToolsController {
private AnchorPane root;
private AnchorPane httpServer;
private AnchorPane ftpServer;
+ private AnchorPane sshClient;
public static final String color_cell = "#f4f4f4";
@@ -260,21 +261,42 @@ public class ServerToolsController {
}
ftpServer(flag);
}
+ if (newValue.getIndex() == 2) {
+ if (sshClient != null){
+ flag = true;
+ }
+ sshClient(flag);
+ }
}
});
}
+ private void sshClient(boolean flag) {
+ listView.getSelectionModel().select(2);
+ if (!flag){
+ try {
+ root = FXMLLoader.load(ResourcesUtils.getResource("ssh-connection"));
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ ftpServer = root;
+ }else {
+ root = ftpServer;
+ }
+ common_method();
+ }
+
private void ftpServer(boolean flag) {
- listView.getSelectionModel().select(0);
+ listView.getSelectionModel().select(1);
if (!flag){
try {
root = FXMLLoader.load(ResourcesUtils.getResource("ftp-server"));
} catch (IOException e) {
e.printStackTrace();
}
- httpServer = root;
+ ftpServer = root;
}else {
- root = httpServer;
+ root = ftpServer;
}
common_method();
}
@@ -298,6 +320,7 @@ public class ServerToolsController {
return switch (player){
case Http_Server -> new Image(ImagePath.path(ImagePath.ImagePathType.MD5));
case Ftp_Server -> new Image(ImagePath.path(ImagePath.ImagePathType.SPRING_SECURITY));
+ case SSH_Client -> new Image(ImagePath.path(ImagePath.ImagePathType.SPRING_SECURITY));
};
}
diff --git a/src/main/java/com/zhangmeng/tools/ssh/SSHService.java b/src/main/java/com/zhangmeng/tools/ssh/SSHService.java
new file mode 100644
index 0000000..6baf71a
--- /dev/null
+++ b/src/main/java/com/zhangmeng/tools/ssh/SSHService.java
@@ -0,0 +1,16 @@
+package com.zhangmeng.tools.ssh;
+
+/**
+ * @author : 芊芊墨客
+ * @version : 1.0
+ * @date : 2023-03-11 16:16
+ * 接口地址: https://blog.51cto.com/zhongmayisheng/5216135
+ */
+public interface SSHService {
+
+ public void initConnection(String USER_UUID_KEY, SSHServiceImpl.SSHConnectInfo sshConnectInfo);
+
+ public void recvHandle(String command, SSHServiceImpl.Type type, String USER_UUID_KEY);
+
+ public void close(String USER_UUID_KEY);
+}
diff --git a/src/main/java/com/zhangmeng/tools/ssh/SSHServiceImpl.java b/src/main/java/com/zhangmeng/tools/ssh/SSHServiceImpl.java
new file mode 100644
index 0000000..b807642
--- /dev/null
+++ b/src/main/java/com/zhangmeng/tools/ssh/SSHServiceImpl.java
@@ -0,0 +1,248 @@
+package com.zhangmeng.tools.ssh;
+
+import com.jcraft.jsch.Channel;
+import com.jcraft.jsch.JSch;
+import com.jcraft.jsch.JSchException;
+import com.jcraft.jsch.Session;
+import javafx.collections.FXCollections;
+import javafx.collections.ObservableList;
+import lombok.extern.slf4j.Slf4j;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.nio.charset.StandardCharsets;
+import java.util.Arrays;
+import java.util.Map;
+import java.util.Properties;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+
+/**
+ * @author : 芊芊墨客
+ * @version : 1.0
+ * @date : 2023-03-11 16:18
+ */
+@Slf4j
+public class SSHServiceImpl implements SSHService {
+
+ //存放ssh连接信息的map
+ private static final Map sshMap = new ConcurrentHashMap<>();
+ //线程池
+ private final ExecutorService executorService = Executors.newCachedThreadPool();
+
+ public static ObservableList message_list = FXCollections.observableArrayList();
+
+ @Override
+ public void initConnection(String USER_UUID_KEY,SSHConnectInfo sshConnectInfo) {
+ JSch jSch = new JSch();
+ sshConnectInfo.setjSch(jSch);
+ //将这个ssh连接信息放入map中
+ sshMap.put(USER_UUID_KEY, sshConnectInfo);
+ }
+
+ @Override
+ public void recvHandle(String command, Type type,String USER_UUID_KEY) {
+
+ if (Type.connect.equals(type)) {
+ //如果是连接请求
+ //找到刚才存储的ssh连接对象
+ SSHConnectInfo sshConnectInfo = (SSHConnectInfo) sshMap.get(USER_UUID_KEY);
+ //启动线程异步处理
+ executorService.execute(() -> {
+ try {
+ //连接到终端
+ connectToSSH(sshConnectInfo);
+ } catch (JSchException | IOException e) {
+ log.error("webssh连接异常");
+ log.error("异常信息:{}", e.getMessage());
+ close(USER_UUID_KEY);
+ }
+ });
+ }
+ if (Type.command.equals(type)) {
+ //如果是发送命令的请求
+ SSHConnectInfo sshConnectInfo = (SSHConnectInfo) sshMap.get(USER_UUID_KEY);
+ if (sshConnectInfo != null) {
+ try {
+ //发送命令到终端
+ transToSSH(sshConnectInfo.getChannel(), command);
+ } catch (IOException e) {
+ log.error("webssh连接异常");
+ log.error("异常信息:{}", e.getMessage());
+ close(USER_UUID_KEY);
+ }
+ }
+ } else {
+ log.error("不支持的操作");
+ close(USER_UUID_KEY);
+ }
+ }
+
+ @Override
+ public void close(String USER_UUID_KEY) {
+ SSHConnectInfo sshConnectInfo = (SSHConnectInfo) sshMap.get(USER_UUID_KEY);
+ if (sshConnectInfo != null) {
+ //断开连接
+ if (sshConnectInfo.getChannel() != null) sshConnectInfo.getChannel().disconnect();
+ //map中移除
+ sshMap.remove(USER_UUID_KEY);
+ }
+ }
+
+ /**
+ * @Description: 使用jsch连接终端
+ * @Param: [cloudSSH, webSSHData, webSocketSession]
+ * @return: void
+ * @Author: NoCortY
+ * @Date: 2020/3/7
+ */
+ private void connectToSSH(SSHConnectInfo sshConnectInfo) throws JSchException, IOException {
+ Session session = null;
+ Properties config = new Properties();
+ config.put("StrictHostKeyChecking", "no");
+ //获取jsch的会话
+ JSch jSch = new JSch();
+ session = jSch.getSession(sshConnectInfo.username, sshConnectInfo.host, sshConnectInfo.port);
+ session.setConfig(config);
+ //设置密码
+ session.setPassword(sshConnectInfo.password);
+ //连接 超时时间30s
+ session.connect(30000);
+
+ //开启shell通道
+ Channel channel = session.openChannel("shell");
+
+ //通道连接 超时时间3s
+ channel.connect(3000);
+
+ //设置channel
+ sshConnectInfo.setChannel(channel);
+
+ //转发消息
+ transToSSH(channel, "\r");
+
+ //读取终端返回的信息流
+ try (InputStream inputStream = channel.getInputStream()) {
+ //循环读取
+ byte[] buffer = new byte[1024];
+ int i = 0;
+ //如果没有数据来,线程会一直阻塞在这个地方等待数据。
+ while ((i = inputStream.read(buffer)) != -1) {
+ sendMessage(Arrays.copyOfRange(buffer, 0, i));
+ }
+ } finally {
+ //断开连接后关闭会话
+ session.disconnect();
+ channel.disconnect();
+ }
+ }
+
+ public void sendMessage(byte[] buffer){
+ message_list.add(buf_to_string(buffer));
+ message_list.add(System.lineSeparator());
+ }
+
+ public static String buf_to_string(byte[] buffer){
+ return new String(buffer, StandardCharsets.UTF_8);
+ }
+
+ /**
+ * @Description: 将消息转发到终端
+ */
+ private void transToSSH(Channel channel, String command) throws IOException {
+ if (channel != null) {
+ OutputStream outputStream = channel.getOutputStream();
+ outputStream.write(command.getBytes());
+ outputStream.flush();
+ }
+ }
+
+ public enum Type{
+ connect("连接"),
+ command("命令"),
+ ;
+
+ private String desc;
+
+ Type(String desc) {
+ this.desc = desc;
+ }
+
+ public String getDesc() {
+ return desc;
+ }
+
+ public void setDesc(String desc) {
+ this.desc = desc;
+ }
+ }
+
+ public static class SSHConnectInfo{
+ public String host;
+ private JSch jSch;
+ private String username;
+ private String password;
+ private int port;
+ private Channel channel;
+
+ public Channel getChannel() {
+ return channel;
+ }
+
+ public String getHost() {
+ return host;
+ }
+
+ public void setHost(String host) {
+ this.host = host;
+ }
+
+ public void setChannel(Channel channel) {
+ this.channel = channel;
+ }
+
+ public SSHConnectInfo() {
+ }
+
+ public SSHConnectInfo(JSch jSch, String username, String password, int port) {
+ this.jSch = jSch;
+ this.username = username;
+ this.password = password;
+ this.port = port;
+ }
+
+ public JSch getjSch() {
+ return jSch;
+ }
+
+ public void setjSch(JSch jSch) {
+ this.jSch = jSch;
+ }
+
+ public String getUsername() {
+ return username;
+ }
+
+ public void setUsername(String username) {
+ this.username = username;
+ }
+
+ public String getPassword() {
+ return password;
+ }
+
+ public void setPassword(String password) {
+ this.password = password;
+ }
+
+ public int getPort() {
+ return port;
+ }
+
+ public void setPort(int port) {
+ this.port = port;
+ }
+ }
+}
diff --git a/src/main/java/com/zhangmeng/tools/utils/ResourcesUtils.java b/src/main/java/com/zhangmeng/tools/utils/ResourcesUtils.java
index 0d3341e..58591d8 100644
--- a/src/main/java/com/zhangmeng/tools/utils/ResourcesUtils.java
+++ b/src/main/java/com/zhangmeng/tools/utils/ResourcesUtils.java
@@ -274,6 +274,7 @@ public class ResourcesUtils {
Http_Server("Http Server工具",0),
Ftp_Server("Ftp Server工具",1),
+ SSH_Client("ssh 连接工具",2),
;
ServerTools(String title, int index) {
diff --git a/src/main/resources/fxml/home.fxml b/src/main/resources/fxml/home.fxml
index b931d52..e8d1c93 100644
--- a/src/main/resources/fxml/home.fxml
+++ b/src/main/resources/fxml/home.fxml
@@ -68,6 +68,7 @@
+
diff --git a/src/main/resources/fxml/ssh-connection.fxml b/src/main/resources/fxml/ssh-connection.fxml
new file mode 100644
index 0000000..1206ec1
--- /dev/null
+++ b/src/main/resources/fxml/ssh-connection.fxml
@@ -0,0 +1,25 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+