当前位置: 首页 > 工具软件 > Apache SSHD > 使用案例 >

SpringBoot:使用Apache SSHD搭建基于JAVA的SFTP服务器

甄文彬
2023-12-01

依赖

服务器端

<dependencies>
   <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter</artifactId>
   </dependency>
   <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-test</artifactId>
      <scope>test</scope>
   </dependency>
   <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-web</artifactId>
   </dependency>
   <dependency>
      <groupId>org.projectlombok</groupId>
      <artifactId>lombok</artifactId>
   </dependency>
   <dependency>
      <groupId>org.apache.sshd</groupId>
      <artifactId>sshd-sftp</artifactId>
      <version>2.8.0</version>
   </dependency>
</dependencies>

客户端

这个版本很重要 jsch 0.1.55可以连接服务端,0.1.54有一处源码不一致就连不了, 报verify false,需要修改sftp服务器的hostkey算法或ec算法长度keysize为256才能连。
如果使用ganymed-ssh2 这种,就需要进一步配置kex和host key算法

<dependency>
    <groupId>com.jcraft</groupId>
    <artifactId>jsch</artifactId>
    <version>0.1.55</version>
</dependency>

配置文件

sftp:
  # 开启
  enabled: true
  # 地址 端口
  host: 127.0.0.1
  port: 1234
  # 存储的文件路径
  base-path: /opt/sftpdir
  # 账密map,1~n组
  user-pwd:
    root: root
    root2: root2

代码

配置类

package com.mysftp.config;

import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;

import java.util.Map;

@Data
@ConfigurationProperties(prefix = "sftp")
public class SftpConfig {

    private boolean enabled = true;

    private String host;

    private int port;

    private String basePath;

    private Map<String, String> userPwd;
}

自动装配

package com.mysftp.config;

import org.apache.sshd.common.file.virtualfs.VirtualFileSystemFactory;
import org.apache.sshd.server.SshServer;
import org.apache.sshd.server.keyprovider.SimpleGeneratorHostKeyProvider;
import org.apache.sshd.server.shell.ProcessShellCommandFactory;
import org.apache.sshd.sftp.server.SftpSubsystemFactory;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.io.IOException;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Arrays;
import java.util.Map;

@ConditionalOnProperty(prefix = "sftp", name = "enabled", matchIfMissing = true)
@EnableConfigurationProperties(SftpConfig.class)
@Configuration
public class SftpServerConfiguration {

    private final SftpConfig sftpConfig;

    public SftpServerConfiguration(SftpConfig sftpConfig) {
        this.sftpConfig = sftpConfig;
    }

    @Bean
    public void sftpServer() {
        //创建SshServer对象
        SshServer sshd = SshServer.setUpDefaultServer();
        sshd.setHost(sftpConfig.getHost());
        //配置端口
        sshd.setPort(sftpConfig.getPort());
        //设置默认的签名文件,如果文件不存在会创建
//        sshd.setKeyPairProvider(new SimpleGeneratorHostKeyProvider(Paths.get("E:\\tmp1\\key")));
//        sshd.setKeyPairProvider(new SimpleGeneratorHostKeyProvider(Paths.get("/opt/key")));
        Map<String, String> userPwd = sftpConfig.getUserPwd();
        //设置用户名和密码进行登录验证
        sshd.setPasswordAuthenticator((username, password, serverSession) -> {
            //这里可以增加逻辑从数据库或其他方式校验用户名和密码
            //返回true则校验成功否则失败
            return userPwd.containsKey(username) && password.equals(userPwd.get(username));
        });
        //设置sftp子系统
        sshd.setSubsystemFactories(Arrays.asList(new SftpSubsystemFactory()));
        //设置sfp默认的访问目录
        Path dir = Paths.get(sftpConfig.getBasePath());

        sshd.setFileSystemFactory(new VirtualFileSystemFactory(dir.toAbsolutePath()));
        //给每个用户分配不同的访问目录
//        sshd.setFileSystemFactory(new VirtualFileSystemFactory(dir.toAbsolutePath()) {
//            @Override
//            public Path getUserHomeDir(SessionContext session) throws IOException {
//                String username = session.getUsername();
//                Path homeDir = getUserHomeDir(username);
//                if (homeDir == null) {
//                    //这里给每个用户修改为默认目录+用户名+dir的目录格式
//                    //可以根据实际的需求修改此处的代码
//                    homeDir = getDefaultHomeDir().resolve(username + "dir");
//                    setUserHomeDir(username, homeDir);
//                }
//                File file = new File(String.valueOf(homeDir));
//                file.mkdirs();
//                return homeDir;
//            }
//        });
        //设置ssh的shell环境
//        sshd.setShellFactory((c) -> {
//            ServerSession session = c.getSession();
//            String username = session.getUsername();
//            //除了root以外的的用户都不允许远程登录
//            if ("root".equals(username)) {
//                return InteractiveProcessShellFactory.INSTANCE.createShell(c);
//            } else {
//                return null;
//            }
//        });
        sshd.setKeyPairProvider(new SimpleGeneratorHostKeyProvider());
        sshd.setCommandFactory(new ProcessShellCommandFactory());
        //启动ssh服务
        try {
            sshd.start();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

参考地址

官网:https://mina.apache.org/sshd-project/

GitHub:https://github.com/apache/mina-sshd

https://gitee.com/mirrors/mina-sshd/

https://github.com/apache/mina-sshd/tree/master/sshd-sftp

https://github.com/apache/mina-sshd/tree/master/sshd-spring-sftp

https://github.com/apache/mina-sshd

https://github.com/apache/mina-sshd/blob/master/docs/sftp.md

https://github.com/apache/mina-sshd/blob/master/docs/server-setup.md

https://zhuanlan.zhihu.com/p/349738684?utm_source=wechat_session&utm_medium=social&utm_oi=547928202685915136&utm_campaign=shareopn

 类似资料: