目录
1. 什么是SFTP
2.java项目中使用JSch
3.Jsch文件上传示例
4.秘钥登录方式怎么传文件的路径呢?
1. 什么是SFTP
SFTP是一个安全文件传送协议,可以为传输文件提供一种安全的加密方法。SFTP 为 SSH的一部份,是一种传输文件到服务器的安全方式。SFTP是使用加密传输认证信息和传输的数据,所以,使用SFTP是非常安全的。但是,由于这种传输方式使用了加密/解密技术,所以传输效率比普通的FTP要低得多,如果您对网络安全性要求更高时,可以使用SFTP代替FTP。
2.java项目中使用JSch
Jsch是一个纯粹的用java实现SSH功能的java library,支持密码登录方式和秘钥登录方式。用密码登录,就是和我们用ftp的账号密码登录一样,比较简单。秘钥登录方式,就需要把客户端的公钥放到SFTP服务器,然后客户端需要用秘钥登录。
3.Jsch文件上传示例
import com.jcraft.jsch.*;
import lombok.Data;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Component;
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;
/**
* 功能简述:<br>
* 详细描述:<br>
*
* @since SFtp工具类
*/
@Data
@Configuration
@Component
public class SFtpUtils {
private static Logger log = LoggerFactory.getLogger(SFtpUtils.class);
/**
* 将指定流文件上传到FTP服务器
*
* @param ftpAddress ftp地址
* @param ftpPort ftp端口
* @param ftpUserName ftp账号
* @param ftpPassowrd ftp密码
* @param ftpFileName 上传到FTP服务器的文件名
* @param ftpPath 上传到FTP服务器指定目录下(如果目录在FTP服务器上不存在,则自动创建)
* @param localFile 本地文件流
* @param privateKeyFile 私钥
* @return
*/
public static boolean uploadFile(String ftpAddress, int ftpPort, String ftpUserName, String ftpPassowrd, String privateKeyFile, String ftpFileName, String ftpPath, InputStream localFile) throws JSchException {
boolean success = false;
ChannelSftp channelSftp = null;
Session jschSession = null;
try {
JSch jsch = new JSch();
// 私钥非空的时候使用私钥进行验证
if (StringUtils.isNotEmpty(privateKeyFile)) {
jsch.addIdentity(privateKeyFile);
}
// 获取到jSch的session, 根据用户名、主机ip、端口号获取一个Session对象
jschSession = jsch.getSession(ftpUserName, ftpAddress, ftpPort);
if (StringUtils.isNotEmpty(privateKeyFile)) {
jschSession.setUserInfo(new SftpAuthKeyUserInfo(privateKeyFile));
} else if (StringUtils.isNotEmpty(ftpPassowrd)) {
jschSession.setPassword(ftpPassowrd);
}
// 通过Session建立连接
Properties sshConfig = new Properties();
sshConfig.put("StrictHostKeyChecking", "no");
jschSession.setConfig(sshConfig);
jschSession.connect();
channelSftp = (ChannelSftp) jschSession.openChannel("sftp");
// sftp管道连接
channelSftp.connect();
// 进入到目标目录,目标目录如果不存在则创建
String[] paths = ftpPath.split("/");
StringBuffer sb = new StringBuffer();
for (String p : paths) {
if (StringUtils.isEmpty(p)) {
continue;
}
sb = sb.append("/" + p);
//循环创建路径
try {
channelSftp.cd(sb.toString());
} catch (SftpException ex) {
channelSftp.mkdir(sb.toString());
channelSftp.cd(sb.toString());
}
}
// 上传文件
channelSftp.put(localFile, ftpFileName);
channelSftp.exit();
success = true;
} catch (SftpException e) {
e.printStackTrace();
log.error("IOException", e);
} finally {
if (channelSftp != null) {
channelSftp.disconnect();
}
if (jschSession != null) {
jschSession.disconnect();
}
if (localFile != null) {
try {
localFile.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return success;
}
/**
* 获取一个已经connect的ChannelSftp对象
* @param ftpAddress Sftp地址
* @param ftpPort 端口号
* @param ftpUserName 账号
* @param ftpPassowrd 密码
* @return
*/
public static ChannelSftp getChannelSftp(String ftpAddress, int ftpPort, String ftpUserName, String ftpPassowrd) {
ChannelSftp channelSftp = null;
Session jschSession = null;
try {
JSch jsch = new JSch();
// 获取到jSch的session, 根据用户名、主机ip、端口号获取一个Session对象
jschSession = jsch.getSession(ftpUserName, ftpAddress, ftpPort);
jschSession.setPassword(ftpPassowrd);
// 通过Session建立连接
Properties sshConfig = new Properties();
sshConfig.put("StrictHostKeyChecking", "no");
jschSession.setConfig(sshConfig);
jschSession.connect();
channelSftp = (ChannelSftp) jschSession.openChannel("sftp");
// sftp管道连接
channelSftp.connect();
return channelSftp;
} catch (JSchException e) {
e.printStackTrace();
log.error("IOException", e);
if (channelSftp != null) {
channelSftp.disconnect();
}
if (jschSession != null) {
jschSession.disconnect();
}
} finally {
}
return null;
}
public static void close(ChannelSftp channelSftp) {
if (channelSftp != null) {
channelSftp.disconnect();
}
}
/**
* UserInfo是jsch包的一个接口
*/
static class SftpAuthKeyUserInfo implements UserInfo{
/**
* ssh private key passphrase
*/
private String passphrase;
/**
* 构造函数需要传秘钥的路径,是秘钥的文件路径,不是流也不是秘钥内容
*/
public SftpAuthKeyUserInfo (String passphrase) {
this.passphrase = passphrase;
}
@Override
public String getPassphrase() {
return passphrase;
}
@Override
public String getPassword() {
return null;
}
@Override
public boolean promptPassword(String message) {
return false;
}
@Override
public boolean promptPassphrase(String message) {
return true;
}
@Override
public boolean promptYesNo(String message) {
return true;
}
@Override
public void showMessage(String message) {
log.info ("SSH Message:{}", message);
}
}
}
4.秘钥登录方式怎么传文件的路径呢?
我在项目中是把秘钥文件放在了resource资源目录下。然后根据项目环境取不同环境的秘钥。
// 获取私钥文件路径
ClassPathResource classPathResource = new ClassPathResource(privateKeyPathEnv + "/id_rsa");
String sftpPrivatePath = classPathResource.getFile().getAbsolutePath();
至于是否还有其他更好获取秘钥文件路径的方式请留言。或者JSch使用秘钥登录还有其他的写法请留言。