首页 > 代码库 > SFTP信任公钥配置及JSCH库

SFTP信任公钥配置及JSCH库

1、SFTP信用公钥配置

1.1 客户端生成密钥对

以DSA举例: 

ssh-keygen –t dsa

执行该命令后,在home/用户名/.ssh目录下,会生成id_dsa和id_dsa.pub两个文件

1.2 将id_dsa.pub公钥文件上传至服务端的home/用户名/.ssh目录下

scp id_dsa.pub 用户名@服务端IP:/home/用户名/.ssh

此时还需要输入密码

1.3服务端添加信任公钥

登录服务端,进入到/home/用户名/.ssh目录,将刚刚拷贝的id_dsa.pub文件的内容加入到authorized_keys文件中

cat id_dsa.pub >> authorized_keys

1.4 服务端分别修改authorized_key文件和.ssh的权限为600700

chmod 600 authorized_keys

chmod 700 .ssh

1.5 测试

在客户端执行:

sftp –oPort=端口 用户名@服务端IP

如果不需要输入密码就可以连上,则说明配置成功

 

2、基于JSCH库的sftp操作

Java代码  
  1. public class SftpUtil {  
  2.     private final static Logger          log       = LoggerFactory.getLogger(SftpUtil.class);  
  3.   
  4.     /** SFTP */  
  5.     public static final String           SFTP      = "sftp";  
  6.     /** 通道 */  
  7.     private ChannelSftp                  channel;  
  8.     /** session */  
  9.     private Session                      session;  
  10.   
  11.     /** 规避多线程并发 */  
  12.     private static ThreadLocal<SftpUtil> sftpLocal = new ThreadLocal<SftpUtil>();  
  13.   
  14.     /** 
  15.      * 获取sftpchannel 
  16.      *  
  17.      * @param connectConfig 连接配置 
  18.      * @return 
  19.      * @throws Exception  
  20.      * @throws JSchException 
  21.      */  
  22.     private void init(ConnectConfig connectConfig) throws Exception {  
  23.         String host = connectConfig.getHost();  
  24.         int port = connectConfig.getPort();  
  25.   
  26.         String userName = connectConfig.getUserName();  
  27.   
  28.         //创建JSch对象  
  29.         JSch jsch = new JSch();  
  30.   
  31.         //添加私钥(信任登录方式)  
  32.         if (StringUtils.isNotBlank(connectConfig.getPrivateKey())) {  
  33.             jsch.addIdentity(connectConfig.getPrivateKey());  
  34.         }  
  35.   
  36.         session = jsch.getSession(userName, host, port);  
  37.         if (log.isInfoEnabled()) {  
  38.             log.info(" JSCH Session created,sftpHost = {}, sftpUserName={}", host, userName);  
  39.         }  
  40.   
  41.         //设置密码  
  42.         if (StringUtils.isNotBlank(connectConfig.getPassWord())) {  
  43.             session.setPassword(connectConfig.getPassWord());  
  44.         }  
  45.   
  46.         Properties config = new Properties();  
  47.         config.put("StrictHostKeyChecking", "no");  
  48.         session.setConfig(config);  
  49.         //设置超时  
  50.         session.setTimeout(connectConfig.getTimeout());  
  51.         //建立连接  
  52.         session.connect();  
  53.         if (log.isInfoEnabled()) {  
  54.             log.info("JSCH Session connected.sftpHost = {}, sftpUserName={}", host, userName);  
  55.         }  
  56.   
  57.         //打开SFTP通道  
  58.         channel = (ChannelSftp) session.openChannel(SFTP);  
  59.         //建立SFTP通道的连接  
  60.         channel.connect();  
  61.         if (log.isInfoEnabled()) {  
  62.             log.info("Connected successfully to sftpHost = {}, sftpUserName={}", host, userName);  
  63.         }  
  64.     }  
  65.   
  66.     /** 
  67.      * 是否已连接 
  68.      *  
  69.      * @return 
  70.      */  
  71.     private boolean isConnected() {  
  72.         return null != channel && channel.isConnected();  
  73.     }  
  74.   
  75.     /** 
  76.      * 获取本地线程存储的sftp客户端 
  77.      *  
  78.      * @return 
  79.      * @throws Exception  
  80.      */  
  81.     public static SftpUtil getSftpUtil(ConnectConfig connectConfig) throws Exception {  
  82.         SftpUtil sftpUtil = sftpLocal.get();  
  83.         if (null == sftpUtil || !sftpUtil.isConnected()) {  
  84.             sftpLocal.set(new SftpUtil(connectConfig));  
  85.         }  
  86.         return sftpLocal.get();  
  87.     }  
  88.   
  89.     /** 
  90.      * 释放本地线程存储的sftp客户端 
  91.      */  
  92.     public static void release() {  
  93.         if (null != sftpLocal.get()) {  
  94.             sftpLocal.get().closeChannel();  
  95.             sftpLocal.set(null);  
  96.         }  
  97.     }  
  98.   
  99.     /** 
  100.      * 构造函数 
  101.      * <p> 
  102.      * 非线程安全,故权限为私有 
  103.      * </p> 
  104.      *  
  105.      * @throws Exception  
  106.      */  
  107.     private SftpUtil(ConnectConfig connectConfig) throws Exception {  
  108.         super();  
  109.         init(connectConfig);  
  110.     }  
  111.   
  112.     /** 
  113.      * 关闭通道 
  114.      *  
  115.      * @throws Exception 
  116.      */  
  117.     public void closeChannel() {  
  118.         if (null != channel) {  
  119.             try {  
  120.                 channel.disconnect();  
  121.             } catch (Exception e) {  
  122.                 log.error("关闭SFTP通道发生异常:", e);  
  123.             }  
  124.         }  
  125.         if (null != session) {  
  126.             try {  
  127.                 session.disconnect();  
  128.             } catch (Exception e) {  
  129.                 log.error("SFTP关闭 session异常:", e);  
  130.             }  
  131.         }  
  132.     }  
  133.   
  134.     /** 
  135.      * 下载文件 
  136.      *  
  137.      * @param downDir 下载目录 
  138.      * @param src 源文件 
  139.      * @param dst 保存后的文件名称或目录 
  140.      * @throws Exception 
  141.      */  
  142.     public void downFile(String downDir, String src, String dst) throws Exception {  
  143.         channel.cd(downDir);  
  144.         channel.get(src, dst);  
  145.     }  
  146.   
  147.     /** 
  148.      * 删除文件 
  149.      *  
  150.      * @param filePath 文件全路径 
  151.      * @throws SftpException 
  152.      */  
  153.     public void deleteFile(String filePath) throws SftpException {  
  154.         channel.rm(filePath);  
  155.     }  
  156.   
  157.     @SuppressWarnings("unchecked")  
  158.     public List<String> listFiles(String dir) throws SftpException {  
  159.         Vector<LsEntry> files = channel.ls(dir);  
  160.         if (null != files) {  
  161.             List<String> fileNames = new ArrayList<String>();  
  162.             Iterator<LsEntry> iter = files.iterator();  
  163.             while (iter.hasNext()) {  
  164.                 String fileName = iter.next().getFilename();  
  165.                 if (StringUtils.equals(".", fileName) || StringUtils.equals("..", fileName)) {  
  166.                     continue;  
  167.                 }  
  168.                 fileNames.add(fileName);  
  169.             }  
  170.             return fileNames;  
  171.         }  
  172.         return null;  
  173.     }  
  174. }  

 说明:

2.1 ConnectConfig包含了建立sftp连接所需要的全部参数信息

2.2 如果按照第一步进行了sftp的信任公钥配置,则需要通过调用jsch的addIdentity方法将密钥对中的私钥id_dsa设置进去
Java代码  
  1. //添加私钥(信任登录方式)  
  2.         if (StringUtils.isNotBlank(connectConfig.getPrivateKey())) {  
  3.             jsch.addIdentity(connectConfig.getPrivateKey());  
  4.         }  
2.3 为了避免频繁的进行连接建立和连接释放操作,一般会定义为单例模式,但存在某些业务场景,需要在同一个线程执行完连续几次完整的业务操作后,将连接释放掉。如果采用单例,那么多线程并发的场景下会出现共享资源竞争导致的并发问题,譬如在B线程执行业务的过程中,A线程将连接释放。因此,可以借助ThreadLocal来避免该问题。
Java代码  
  1. /** 
  2.      * 获取本地线程存储的sftp客户端 
  3.      *  
  4.      * @return 
  5.      * @throws Exception  
  6.      */  
  7.     public static SftpUtil getSftpUtil(ConnectConfig connectConfig) throws Exception {  
  8.         SftpUtil sftpUtil = sftpLocal.get();  
  9.         if (null == sftpUtil || !sftpUtil.isConnected()) {  
  10.             sftpLocal.set(new SftpUtil(connectConfig));  
  11.         }  
  12.         return sftpLocal.get();  
  13.     }  
  14.   
  15.     /** 
  16.      * 释放本地线程存储的sftp客户端 
  17.      */  
  18.     public static void release() {  
  19.         if (null != sftpLocal.get()) {  
  20.             sftpLocal.get().closeChannel();  
  21.             sftpLocal.set(null);  
  22.         }  
  23.     }