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操作

public class SftpUtil {
    private final static Logger          log       = LoggerFactory.getLogger(SftpUtil.class);

    /** SFTP */
    public static final String           SFTP      = "sftp";
    /** 通道 */
    private ChannelSftp                  channel;
    /** session */
    private Session                      session;

    /** 规避多线程并发 */
    private static ThreadLocal sftpLocal = new ThreadLocal();

    /**
     * 获取sftpchannel
     * 
     * @param connectConfig 连接配置
     * @return
     * @throws Exception 
     * @throws JSchException
     */
    private void init(ConnectConfig connectConfig) throws Exception {
        String host = connectConfig.getHost();
        int port = connectConfig.getPort();

        String userName = connectConfig.getUserName();

        //创建JSch对象
        JSch jsch = new JSch();

        //添加私钥(信任登录方式)
        if (StringUtils.isNotBlank(connectConfig.getPrivateKey())) {
            jsch.addIdentity(connectConfig.getPrivateKey());
        }

        session = jsch.getSession(userName, host, port);
        if (log.isInfoEnabled()) {
            log.info(" JSCH Session created,sftpHost = {}, sftpUserName={}", host, userName);
        }

        //设置密码
        if (StringUtils.isNotBlank(connectConfig.getPassWord())) {
            session.setPassword(connectConfig.getPassWord());
        }

        Properties config = new Properties();
        config.put("StrictHostKeyChecking", "no");
        session.setConfig(config);
        //设置超时
        session.setTimeout(connectConfig.getTimeout());
        //建立连接
        session.connect();
        if (log.isInfoEnabled()) {
            log.info("JSCH Session connected.sftpHost = {}, sftpUserName={}", host, userName);
        }

        //打开SFTP通道
        channel = (ChannelSftp) session.openChannel(SFTP);
        //建立SFTP通道的连接
        channel.connect();
        if (log.isInfoEnabled()) {
            log.info("Connected successfully to sftpHost = {}, sftpUserName={}", host, userName);
        }
    }

    /**
     * 是否已连接
     * 
     * @return
     */
    private boolean isConnected() {
        return null != channel && channel.isConnected();
    }

    /**
     * 获取本地线程存储的sftp客户端
     * 
     * @return
     * @throws Exception 
     */
    public static SftpUtil getSftpUtil(ConnectConfig connectConfig) throws Exception {
        SftpUtil sftpUtil = sftpLocal.get();
        if (null == sftpUtil || !sftpUtil.isConnected()) {
            sftpLocal.set(new SftpUtil(connectConfig));
        }
        return sftpLocal.get();
    }

    /**
     * 释放本地线程存储的sftp客户端
     */
    public static void release() {
        if (null != sftpLocal.get()) {
            sftpLocal.get().closeChannel();
            sftpLocal.set(null);
        }
    }

    /**
     * 构造函数
     * 

* 非线程安全,故权限为私有 *

* * @throws Exception */ private SftpUtil(ConnectConfig connectConfig) throws Exception { super(); init(connectConfig); } /** * 关闭通道 * * @throws Exception */ public void closeChannel() { if (null != channel) { try { channel.disconnect(); } catch (Exception e) { log.error("关闭SFTP通道发生异常:", e); } } if (null != session) { try { session.disconnect(); } catch (Exception e) { log.error("SFTP关闭 session异常:", e); } } } /** * 下载文件 * * @param downDir 下载目录 * @param src 源文件 * @param dst 保存后的文件名称或目录 * @throws Exception */ public void downFile(String downDir, String src, String dst) throws Exception { channel.cd(downDir); channel.get(src, dst); } /** * 删除文件 * * @param filePath 文件全路径 * @throws SftpException */ public void deleteFile(String filePath) throws SftpException { channel.rm(filePath); } @SuppressWarnings("unchecked") public List listFiles(String dir) throws SftpException { Vector files = channel.ls(dir); if (null != files) { List fileNames = new ArrayList(); Iterator iter = files.iterator(); while (iter.hasNext()) { String fileName = iter.next().getFilename(); if (StringUtils.equals(".", fileName) || StringUtils.equals("..", fileName)) { continue; } fileNames.add(fileName); } return fileNames; } return null; } }

 说明:

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

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

    /**
     * 释放本地线程存储的sftp客户端
     */
    public static void release() {
        if (null != sftpLocal.get()) {
            sftpLocal.get().closeChannel();
            sftpLocal.set(null);
        }
    }

你可能感兴趣的:(技术笔记小点滴)