JSch 是SSH2的纯 Java 实现 。
JSch 允许您连接到 sshd 服务器并使用端口转发、X11 转发、文件传输等,可以将其功能集成到您自己的 Java 程序中。JSch 是在BSD 风格许可下获得许可的。
JSCH 官网:http://www.jcraft.com/jsch/
zip文件中有很多demo.
jar为依赖jar
maven 依赖
<dependency>
<groupId>com.jcraft</groupId>
<artifactId>jsch</artifactId>
<version>0.1.55</version>
</dependency>
测试代码
import com.jcraft.jsch.*;
import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import java.io.*;
import java.util.Properties;
@Slf4j
public class SshTest {
private String charset = "UTF-8"; // 设置编码格式
private static String userName = "kevin"; // 用户名
private static String passWord= "1"; // 登录密码
private static String host = "192.168.10.101"; // 主机IP
private static int port = 22; //默认端口
private static JSch jsch;
private static Session session;
private static ChannelSftp channelSftp;
@BeforeAll
public static void createConn() throws JSchException {
JSch.setLogger(new Log4JSch()); // detail log for JSch.
jsch = new JSch();
// jsch = new KeyGen().keyGenTest();
// 密钥方式
jsch.setKnownHosts("C:\\Users\\Admin\\.ssh\\known_hosts");
// jsch.addIdentity("~/.ssh/id_rsa", "~/.ssh/id_rsa.pub", null);
// jsch.addIdentity("C:\\Users\\Admin\\.ssh\\id_rsa", "C:\\Users\\Admin\\.ssh\\id_rsa.pub", null);
String privKeyPath = "C:\\Users\\Admin\\.ssh\\id_rsa";
jsch.addIdentity(privKeyPath);
session = jsch.getSession(userName, host, port);
// 密码方式
// session.setPassword(passWord);
Properties config = new Properties();
/*
* 在代码里需要跳过检测。否则会报错找不到主机
* Test ignored.
* com.jcraft.jsch.JSchException: UnknownHostKey: 192.168.10.101. RSA key fingerprint is 10:92:98:45:d2:ea:6b:8f:c1:43:e5:df:86:e5:ae:3c
*/
config.put("StrictHostKeyChecking", "no");
session.setConfig(config); // 为Session对象设置properties
int timeout = 30000;
session.setTimeout(timeout); // 设置timeout时间
session.connect(); // 通过Session建立与远程服务器的连接回话
log.info("connect server host: " + host);
}
/**
* 关闭连接
*/
@AfterAll
public static void disconnect(){
log.info("disconnect...");
if (channelSftp != null && channelSftp.isConnected()) {
channelSftp.disconnect();
}
if(session != null && session.isConnected()){
session.disconnect();
}
}
@Test
public void downloadFile() throws JSchException, FileNotFoundException, SftpException {
channelSftp = (ChannelSftp) session.openChannel("sftp");
channelSftp.connect();
log.info("start download channel file!");
String directory = "/tmp";
channelSftp.cd(directory);
String saveDir = "D:\\desktop\\"+System.currentTimeMillis()+".txt";
File file = new File(saveDir);
String downloadFile = "Test.java";
channelSftp.get(downloadFile, new FileOutputStream(file));
log.info("Download Success!");
channelSftp.disconnect();
log.info("end execute channel sftp!");
}
@Test
public void uploadFile() throws JSchException, SftpException, FileNotFoundException {
channelSftp = (ChannelSftp) session.openChannel("sftp");
channelSftp.connect();
log.info("start upload channel file!");
String directory = "/tmp";
channelSftp.cd(directory);
File file = new File("D:\\desktop\\Test.java");
channelSftp.put(new FileInputStream(file), file.getName().replace(".", System.currentTimeMillis()+"."));
log.info("Upload Success!");
channelSftp.disconnect();
log.info("end execute channel sftp!");
}
@Test
public void execShell() throws JSchException, IOException {
ChannelExec channelExec = (ChannelExec) session.openChannel("exec");
String cmd = "pwd";
channelExec.setCommand(cmd); //添加传入进来的shell命令
channelExec.setErrStream(System.err);//通道连接错误信息提示
channelExec.connect();
log.info("start execute channel command!");
try(BufferedReader in = new BufferedReader(new InputStreamReader(channelExec.getInputStream()))) {
String msg;
log.info("start read!");
while ((msg = in.readLine()) != null) {
log.info("命令返回信息:{}", msg);
}
} catch (IOException e) {
e.printStackTrace();
}
channelExec.disconnect();
log.info("end execute channel command!");
}
}
JSch 详细日志实现。 JSch.setLogger(new Log4JSch());
import com.jcraft.jsch.Logger;
import java.util.HashMap;
public class Log4JSch implements Logger {
private static HashMap<String, String> name = new HashMap();
static {
name.put(String.valueOf(DEBUG), "DEBUG");
name.put(String.valueOf(INFO), "INFO");
name.put(String.valueOf(WARN), "WARN");
name.put(String.valueOf(ERROR), "ERROR");
name.put(String.valueOf(FATAL), "FATAL");
}
@Override
public boolean isEnabled(int i) {
return true;
}
@Override
public void log(int level, String message) {
System.err.println(name.get(String.valueOf(level)) + ": " + message);
}
}
问题1
com.jcraft.jsch.JSchException: invalid privatekey: [B@17f7cd29
查看id_rsa文件,内容如下
-----BEGIN OPENSSH PRIVATE KEY-----
b3BlbnNzaC...
...
...
...MAECAwQF
-----END OPENSSH PRIVATE KEY-----
解决方案:
Jsch好像不支持上面的私钥格式,要解决这个问题,我们可以使用ssh-keygen将私钥格式转换为RSAorpem模式,再次运行上面的程序。
$ ssh-keygen -p -f ~/.ssh/id_rsa -m pem
重新检查私钥内容,它应该以BEGIN RSA.
-----BEGIN RSA PRIVATE KEY-----
MIIG4wIBAAK...
...
...
...E428GBDI4
-----END RSA PRIVATE KEY-----
再次尝试连接正常。
Admin@DESKTOP-91JEC09 MINGW64 ~
$ ssh kevin@hadoop101
Last login: Wed Oct 20 14:28:41 2021 from 192.168.10.1
[kevin@hadoop101 ~]$ client_loop: send disconnect: Connection reset by peer
Admin@DESKTOP-91JEC09 MINGW64 ~
$ ssh-keygen -p -f C:\\Users\\Admin\\.ssh\\id_rsa -m pem
Key has comment 'Admin@DESKTOP-91JEC09'
Enter new passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved with the new passphrase.
Admin@DESKTOP-91JEC09 MINGW64 ~
$ ssh kevin@hadoop101
Last login: Wed Oct 20 15:43:57 2021 from 192.168.10.1
参考文档:
https://mkyong.com/java/jsch-invalid-privatekey-exception/
http://www.jcraft.com/jsch/