1. 概念
1.1. JSch
- JSch 是SSH2的一个纯Java实现。它允许你连接到一个 sshd 服务器,使用端口转发,X11转发,文件传输等等。
- 说白了就是以 Java 的方式通过 jsch 连接,来对服务器进行操作。
2. 具体案例
2.1. 使用账号密码登陆并执行指令
2.1.1. 引入依赖
2.1.1.1. 可使用com.github.mwiede依赖
<dependency>
<groupId>com.github.mwiede</groupId>
<artifactId>jsch</artifactId>
<version>0.2.16</version>
</dependency>
2.1.1.2. 也可使用com.jcraft的依赖。但使用这个依赖,在windows中读取密钥文件会出现异常,在linux中不会出现异常。私钥文件应使用 UNIX 样式的行结束符(LF),而非 Windows 样式的行结束符(CRLF)。
<dependency>
<groupId>com.jcraft</groupId>
<artifactId>jsch</artifactId>
<version>0.1.55</version>
</dependency>
2.1.2. 远程登陆并执行指令
@GetMapping("/executeCommand")
public String executeRemoteCommand() {
String host = ymlConfig.getHost();
String username = ymlConfig.getUsername();
String password = ymlConfig.getPassword();
System.out.println(System.getProperty("user.name"));
String command = "ls;touch aa.txt";
RemoteCommandExecutor executor = new RemoteCommandExecutor();
return executor.executeRemoteCommand(host, username, password, command);
}
/**
* 这段代码主要用于执行单个命令并返回结果,不支持连续的交互式会话。
* 使用这个是可以执行ssh指令的,但是会一直没有响应,查看ssh指令远程的主机,是可以看到远程登陆的日志。
* @param host
* @param username
* @param password
* @param command
* @return
*/
public String executeRemoteCommand(String host, String username, String password, String command) {
JSch jsch = new JSch();
Session session = null;
try {
session = jsch.getSession(username, host, 22);
session.setConfig("StrictHostKeyChecking", "no");
session.setPassword(password);
session.connect();
ChannelExec channel = (ChannelExec) session.openChannel("exec");
// 设置环境变量和 Maven 命令
String preCommand = "export PATH=$PATH:/bin:/usr/bin:/root/apache-maven-3.8.5/bin:/root/.bashrc:/etc/profile;source /root/.bashrc;source /etc/profile && ";
channel.setCommand(preCommand + command);
InputStream in = channel.getInputStream();
// 连接通道
channel.connect();
// 读取输出
BufferedReader reader = new BufferedReader(new InputStreamReader(in));
StringBuilder output = new StringBuilder();
String line;
while ((line = reader.readLine()) != null) {
output.append(line).append("\n");
}
// 关闭连接
channel.disconnect();
session.disconnect();
return output.toString();
} catch (JSchException | java.io.IOException e) {
e.printStackTrace();
return "Exception occurred: " + e.getMessage();
}
}
2.1.3. 通过跳板主机连接到目标主机,并在目标主机上执行命令
public void executeRemoteCommand() {
String jumpHost = "";
int jumpPort = 22;
String jumpUser = "root";
String jumpPassword = "";
String targetHost = "";
int targetPort = 22;
String targetUser = "root";
String targetPassword = "";
int forwardedPort = 12345;
try {
JSch jsch = new JSch();
// Establish SSH session with jump host
Session jumpSession = jsch.getSession(jumpUser, jumpHost, jumpPort);
jumpSession.setPassword(jumpPassword);
jumpSession.setConfig("StrictHostKeyChecking", "no");
jumpSession.connect();
// Execute a command on the jump host
ChannelExec jumpChannelExec = (ChannelExec) jumpSession.openChannel("exec");
jumpChannelExec.setCommand("touch newfile.txt");
jumpChannelExec.connect();
// Set up port forwarding for the target host through the jump host
int assignedPort = jumpSession.setPortForwardingL(forwardedPort, targetHost, targetPort);
// Establish SSH session with target host through the jump host
Session targetSession = jsch.getSession(targetUser, "localhost", assignedPort);
targetSession.setPassword(targetPassword);
targetSession.setConfig("StrictHostKeyChecking", "no");
targetSession.connect();
// Execute a command on the target host
ChannelExec channelExec = (ChannelExec) targetSession.openChannel("exec");
channelExec.setCommand("touch newfile.txt");
channelExec.connect();
// Display output of the command
InputStream commandOutput = channelExec.getInputStream();
BufferedReader reader = new BufferedReader(new InputStreamReader(commandOutput));
String line;
while ((line = reader.readLine()) != null) {
System.out.println(line);
}
// Disconnect the channel and sessions
jumpChannelExec.disconnect();
channelExec.disconnect();
targetSession.disconnect();
jumpSession.disconnect();
} catch (Exception e) {
e.printStackTrace();
}
}
2.2. 使用私钥登陆并执行指令
2.2.1. 引入依赖
2.1.1.1. 可使用com.github.mwiede依赖
<dependency>
<groupId>com.github.mwiede</groupId>
<artifactId>jsch</artifactId>
<version>0.2.16</version>
</dependency>
2.1.1.2. 也可使用com.jcraft的依赖。但使用这个依赖,在windows中读取密钥文件会出现异常,在linux中不会出现异常。私钥文件应使用 UNIX 样式的行结束符(LF),而非 Windows 样式的行结束符(CRLF)。
<dependency>
<groupId>com.jcraft</groupId>
<artifactId>jsch</artifactId>
<version>0.1.55</version>
</dependency>
2.2.2. 远程登陆并执行指令
/**
* 使用私钥登陆服务器,并使用服务器相关指令进行操作。
* @return
*/
@GetMapping("/usePrivateKey")
public String usePrivateKeyLogin() {
String command = "ls"; // The command you want to execute
String host = ymlConfig.getHost();
String username = ymlConfig.getUsername();
String privateKeyPath = ymlConfig.getPrivateKeyPath();
SSHService sshService = new SSHService(host, username, privateKeyPath);
sshService.executeCommand(command);
return "执行完成";
}
public class SSHService {
private String host;
private String username;
private String privateKeyPath;
public SSHService(String host, String username, String privateKeyPath) {
this.host = host;
this.username = username;
this.privateKeyPath = privateKeyPath;
}
public void executeCommand(String command) {
Session session = null;
Channel channel = null;
try {
JSch jsch = new JSch();
jsch.addIdentity(privateKeyPath);
session = jsch.getSession(username, host, 22);
Properties config = new Properties();
config.put("StrictHostKeyChecking", "no");
session.setConfig(config);
session.connect();
channel = session.openChannel("exec");
((ChannelExec) channel).setCommand(command);
channel.setInputStream(null);
((ChannelExec)channel).setErrStream(System.err);
channel.connect();
// Read the output from the remote host
InputStream input = channel.getInputStream();
try (BufferedReader reader = new BufferedReader(new InputStreamReader(input))) {
String line;
while ((line = reader.readLine()) != null) {
System.out.println(line);
}
}
channel.disconnect();
session.disconnect();
} catch (Exception e) {
e.printStackTrace();
} finally {
if (session != null) {
session.disconnect();
}
if (channel != null) {
channel.disconnect();
}
}
}
}