SFTP第一篇——搭建SFTP Server
一、Mac搭建Sftp Server
1、检查ftp工具
打开命令行,输入“ftp --help”,检查是否已经安装ftp工具。如果没有,通过以下命令安装:
-
brew install telnet
-
brew install inetutils
-
brew link --overwrite inetutils
如果没有brew,通过以下命令安装:
/usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
2、运行ftp server
- sudo -s launchctl load -w /System/Library/LaunchDaemons/ftp.plist
- sudo -s launchctl unload -w /System/Library/LaunchDaemons/ftp.plist
- ftp localhost
第一个命令,运行ftp server。同理,第二个是关闭ftp server。第三条命令是连接到该本地ftp server。
3、运行sftp server
在System preferences → shared → Remote login中选择允许访问,即可开启sftp server。然后输入sftp localhost即可连接到该sftp server。
二、搭建嵌入式Sftp Server
1、导入依赖
org.apache.sshd sshd-sftp 2.2.0
2、EmbeddedSftpServer
@Slf4j
public class EmbeddedSftpServer implements InitializingBean, SmartLifecycle {public static final int PORT = 0;private final SshServer server = SshServer.setUpDefaultServer();private volatile int port;private volatile boolean running;private DefaultSftpSessionFactory defaultSftpSessionFactory;public void setPort(int port) {this.port = port;}public void setDefaultSftpSessionFactory(DefaultSftpSessionFactory defaultSftpSessionFactory) {this.defaultSftpSessionFactory = defaultSftpSessionFactory;}@Overridepublic void afterPropertiesSet() throws Exception {final PublicKey allowedKey = decodePublicKey();this.server.setPublickeyAuthenticator((username, key, session) -> key.equals(allowedKey));this.server.setPort(this.port);this.server.setKeyPairProvider(new SimpleGeneratorHostKeyProvider(new File("hostKey.ser").toPath()));server.setSubsystemFactories(Collections.singletonList(new SftpSubsystemFactory()));final String pathname = System.getProperty("java.io.tmpdir") + File.separator + "sftpTest" + File.separator;log.info("create temp folder :: " + pathname);new File(pathname).mkdirs();server.setFileSystemFactory(new VirtualFileSystemFactory(Paths.get(pathname)));}private PublicKey decodePublicKey() throws Exception {InputStream stream = new ClassPathResource("/keys/sftp_rsa.pub").getInputStream();byte[] keyBytes = StreamUtils.copyToByteArray(stream);// strip any newline charswhile (keyBytes[keyBytes.length - 1] == 0x0a || keyBytes[keyBytes.length - 1] == 0x0d) {keyBytes = Arrays.copyOf(keyBytes, keyBytes.length - 1);}byte[] decodeBuffer = Base64Utils.decode(keyBytes);ByteBuffer bb = ByteBuffer.wrap(decodeBuffer);int len = bb.getInt();byte[] type = new byte[len];bb.get(type);if ("ssh-rsa".equals(new String(type, "UTF-8"))) {BigInteger e = decodeBigInt(bb);BigInteger m = decodeBigInt(bb);RSAPublicKeySpec spec = new RSAPublicKeySpec(m, e);return KeyFactory.getInstance("RSA").generatePublic(spec);} else {throw new IllegalArgumentException("Only supports RSA");}}private BigInteger decodeBigInt(ByteBuffer bb) {int len = bb.getInt();byte[] bytes = new byte[len];bb.get(bytes);return new BigInteger(bytes);}@Overridepublic boolean isAutoStartup() {return PORT == this.port;}@Overridepublic int getPhase() {return Integer.MAX_VALUE;}@Overridepublic void start() {try {this.server.start();log.info("Embedded Sftp Server started");this.defaultSftpSessionFactory.setPort(this.server.getPort());this.running = true;} catch (IOException e) {log.error("Embedded Sftp Server starting failure", e);throw new IllegalStateException(e);}}@Overridepublic void stop(Runnable callback) {stop();callback.run();}@Overridepublic void stop() {if (this.running) {try {server.stop(true);log.info("Embedded Sftp Server stopped");} catch (Exception e) {log.info("Embedded Sftp Server stop failure", e);throw new IllegalStateException(e);} finally {this.running = false;}}}@Overridepublic boolean isRunning() {return this.running;}
}
3、key文件
sftp_rsa(Private key)
public class SftpTestUtils {private static final String SFTP_TEMP_FOLDER = "sftpTempFolder";public static void createTestFiles(RemoteFileTemplate template, final String... fileNames) {if (template != null) {final ByteArrayInputStream stream = new ByteArrayInputStream("TestData".getBytes());template.execute((SessionCallback) session -> {try {session.mkdir(SFTP_TEMP_FOLDER);} catch (Exception e) {assertThat(e.getMessage(), containsString("failed to create"));}for (int i = 0; i < fileNames.length; i++) {stream.reset();session.write(stream, SFTP_TEMP_FOLDER + "/" + fileNames[i]);}return null;});}}public static void cleanUp(RemoteFileTemplate template, final String... fileNames) {if (template != null) {template.execute((SessionCallback) session -> {for (int i = 0; i < fileNames.length; i++) {try {// delete temp filesession.remove(SFTP_TEMP_FOLDER + "/" + fileNames[i]);} catch (IOException e) {}}// delete temp foldersession.rmdir(SFTP_TEMP_FOLDER);return null;});}}public static boolean fileExists(RemoteFileTemplate template, final String... fileNames) {if (template != null) {return template.execute(session -> {ChannelSftp channel = (ChannelSftp) session.getClientInstance();for (int i = 0; i < fileNames.length; i++) {try {SftpATTRS stat = channel.stat(SFTP_TEMP_FOLDER + "/" + fileNames[i]);if (stat == null) {System.out.println("stat returned null for " + fileNames[i]);return false;}} catch (SftpException e) {System.out.println("Remote file not present: " + e.getMessage() + ": " + fileNames[i]);return false;}}return true;});} else {return false;}}}
该工具类用来创建一些临时目录和文件,供测试类调用。
5、SftpTestConfig配置类
@TestConfiguration
public class SftpTestConfig {@Beanpublic DefaultSftpSessionFactory defaultSftpSessionFactory() {DefaultSftpSessionFactory factory = new DefaultSftpSessionFactory();factory.setPort(0);factory.setHost("localhost");factory.setUser("user");factory.setAllowUnknownKeys(true);factory.setPrivateKey(new ClassPathResource("/keys/sftp_rsa"));factory.setPrivateKeyPassphrase("password");return factory;}@Beanpublic CachingSessionFactory cachingSessionFactory() {return new CachingSessionFactory(defaultSftpSessionFactory());}@Beanpublic EmbeddedSftpServer embeddedSftpServer() {EmbeddedSftpServer sftpServer = new EmbeddedSftpServer();sftpServer.setPort(0);sftpServer.setDefaultSftpSessionFactory(defaultSftpSessionFactory());return sftpServer;}
}
6、测试类
@Slf4j
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = {SftpTestConfig.class}, loader = AnnotationConfigContextLoader.class)
public class SpringSftpTest {@Autowiredprivate CachingSessionFactory cachingSessionFactory;private RemoteFileTemplate template;private String file1 = "a.txt";private String file2 = "b.txt";private String file3 = "c.txt";@Beforepublic void init() {template = new RemoteFileTemplate<>(cachingSessionFactory);// create test fileSftpTestUtils.createTestFiles(template, file1, file2, file3);}@Afterpublic void destroy() {// delete all temp file and folderSftpTestUtils.cleanUp(template, file1, file2, file3);}@Testpublic void testListFiles() {Assert.assertTrue(template.exists("/sftpTempFolder"));ChannelSftp.LsEntry[] lsEntries = template.list("/sftpTempFolder");// bypass '.' and '..' folderArrays.stream(lsEntries).filter(lsEntry -> !lsEntry.getFilename().startsWith(".")).forEach(lsEntry -> {log.info(lsEntry.getLongname());Assert.assertTrue(lsEntry.getFilename().endsWith(".txt"));});}
}
这里采用Spring-integration-sftp做sftp开发,jsch的话也一样,配置好host、port等,连接到嵌入式sftp server即可。
本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!
