基于Apache MINA SSHD配置及應用

Apache MINA SSHD 是一個基于 Java 的 SSH 服務器和客戶端實現,它是 Apache MINA 項目的一部分,提供了完整的 SSH 協議支持。

主要特性

  1. SSH 協議支持

    • 支持 SSH2 協議

    • 兼容大多數 SSH 客戶端

    • 支持多種加密算法和密鑰交換方法

  2. 服務器功能

    • 可嵌入的 SSH 服務器

    • 支持密碼認證和公鑰認證

    • 支持端口轉發

    • 可自定義的 shell 和命令執行

  3. 客戶端功能

    • 完整的 SSH 客戶端實現

    • 支持交互式和非交互式會話

    • 支持 SCP 和 SFTP 文件傳輸

  4. 具體配置

import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import org.apache.sshd.client.SshClient;
import org.apache.sshd.client.session.ClientSession;
import org.apache.sshd.sftp.client.SftpClient;
import org.apache.sshd.sftp.client.SftpClientFactory;
import org.apache.sshd.sftp.common.SftpConstants;
import org.springframework.lang.NonNull;
import java.io.ByteArrayOutputStream;
import java.io.*;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.function.Consumer;
import java.util.function.Function;/*** SshClient服務類** @author gengzhy* @since 2025/5/29 16:57*/
@Slf4j
public class SshClientService {private final SshClient sshClient;private final SftpProperties properties;public SshClientService(SshClient sshClient, SftpProperties properties) {this.sshClient = sshClient;this.properties = properties;}/*** 讀取文件** @param filePath - 文件路徑* @return - Bytes*/public byte[] readOnce(@NonNull String filePath) throws IOException {return executeInternal(session -> {try (SftpClient sftpClient = sftpClient(session)) {SftpClient.Attributes stat = beforeReadCheck(sftpClient, filePath);try (InputStream in = new BufferedInputStream(sftpClient.read(filePath))) {ByteArrayOutputStream out = new ByteArrayOutputStream((int) stat.getSize());byte[] buffer = new byte[8192];int read;while ((read = in.read(buffer, 0, buffer.length)) != -1) {out.write(buffer, 0, read);}return out.toByteArray();}} catch (IOException e) {Throwable ex = getRootCause(e);log.error("sftp 讀取文件異常: {}", ex.getMessage(), ex);throw new RuntimeException(ex.getMessage(), ex);}});}/*** 讀取文件** @param filePath - 文件路徑* @return - Bytes*/public List<String> readLines(@NonNull String filePath) throws IOException {return readLines(filePath, null);}/*** 讀取文件** @param filePath     - 文件路徑* @param lineConsumer - 讀取的數據行消費者* @return - Bytes*/public List<String> readLines(@NonNull String filePath, Consumer<String> lineConsumer) throws IOException {return executeInternal(session -> {try (SftpClient sftpClient = sftpClient(session)) {beforeReadCheck(sftpClient, filePath);try (BufferedReader br = new BufferedReader(new InputStreamReader(sftpClient.read(filePath), StandardCharsets.UTF_8))) {List<String> data = new ArrayList<>();String line;while ((line = br.readLine()) != null) {data.add(line);if (lineConsumer != null) {lineConsumer.accept(line);}}return data;}} catch (IOException e) {Throwable ex = getRootCause(e);log.error("sftp 讀取文件異常: {}", ex.getMessage(), ex);throw new RuntimeException(ex.getMessage(), ex);}});}/*** 創建文件** @param filePath - 文件路徑*/public void writeOnce(@NonNull String filePath, byte[] data) throws IOException {executeInternal(session -> {try (SftpClient sftpClient = sftpClient(session)) {mkDirsIfNotExists(sftpClient, getFileParentPath(filePath));try (SftpClient.CloseableHandle handle = sftpClient.open(filePath, SftpClient.OpenMode.Create, SftpClient.OpenMode.Write, SftpClient.OpenMode.Read)) {sftpClient.write(handle, 0L, data);}return null;} catch (IOException e) {Throwable ex = getRootCause(e);log.error("sftp 創建文件異常: {}", ex.getMessage(), ex);throw new RuntimeException(ex.getMessage(), ex);}});}/*** 遞歸創建目錄(等效于 mkdir -p)** @param sftpClient SFTP 客戶端* @param dirPath    目標路徑(如 "/a/b/c")*/public void mkDirsIfNotExists(SftpClient sftpClient, String dirPath) throws IOException {if (dirPath == null) {return;}String[] parts = dirPath.split("/");StringBuilder currentPath = new StringBuilder();for (String part : parts) {if (part.isEmpty()) {continue;}currentPath.append("/").append(part);String path = currentPath.toString();if (stat(sftpClient, path) == null) {sftpClient.mkdir(path);}}}/*** 提供一個便于擴展的內容部執行方法,主要是基于{@link ClientSession}對象的一些列操作* <p>* 如:* 創建sftp客戶端對象:{@link SftpClientFactory#instance()#createSftpClient(ClientSession)}* 創建shell執行命令對象:{@link ClientSession#createExecChannel(String)}}** @param execCall - 基于{@link ClientSession}對象的回調* @param <T>      - 返回數據類型* @return - obj*/public <T> T executeInternal(Function<ClientSession, T> execCall) throws IOException {try (ClientSession session = session()) {return execCall != null ? execCall.apply(session) : null;} catch (IOException e) {log.error("創建ssh會話異常·: {}", e.getMessage(), e);throw new IOException("創建ssh會話異常: " + e.getMessage(), e);}}private SftpClient.Attributes beforeReadCheck(SftpClient sftpClient, String filePath) {SftpClient.Attributes stat = stat(sftpClient, filePath);if (stat == null) {throw new RuntimeException("文件不存在【{" + filePath + "}】");}Asserts.isTrue(stat.isRegularFile(), "不支持的文件類型:" + FileType.getByActualType(stat.getType()));Asserts.isTrue(stat.getSize() <= Integer.MAX_VALUE, "文件過大");return stat;}private String getFileParentPath(String filePath) {String path = filePath.replaceAll("[\\\\/]+", "/");int index = path.lastIndexOf('/');return index == -1 ? null : path.substring(0, index);}/*** 獲取文件信息,不存在返回null** @param sftpClient - sftp客戶端* @param filePath   - 文件路徑*/private SftpClient.Attributes stat(SftpClient sftpClient, String filePath) {try {return sftpClient.stat(filePath);} catch (IOException e) {return null;}}private SftpClient sftpClient(ClientSession session) throws IOException {return SftpClientFactory.instance().createSftpClient(session);}private ClientSession session() throws IOException {synchronized (sshClient) {if (!sshClient.isStarted()) {sshClient.start();}}ClientSession session = sshClient.connect(properties.getUsername(), properties.getHost(), properties.getPort()).verify(properties.getConnectTimeout()).getSession();session.addPasswordIdentity(properties.getPassword());session.auth().verify(properties.getAuthTimeout());return session;}private Throwable getRootCause(Throwable ex) {while (ex.getCause() != null) {ex = ex.getCause();}return ex;}@Getter@AllArgsConstructorprivate enum FileType {file(SftpConstants.SSH_FILEXFER_TYPE_REGULAR),dir(SftpConstants.SSH_FILEXFER_TYPE_DIRECTORY),symlink(SftpConstants.SSH_FILEXFER_TYPE_SYMLINK),special_file(SftpConstants.SSH_FILEXFER_TYPE_SPECIAL),SOCKET(SftpConstants.SSH_FILEXFER_TYPE_SOCKET),unknown(SftpConstants.SSH_FILEXFER_TYPE_UNKNOWN),;private final int actualType;public static FileType getByActualType(int actualType) {return Arrays.stream(FileType.values()).filter(item -> item.actualType == actualType).findFirst().orElseThrow(() -> new RuntimeException("Unknown file type: " + actualType));}}
}
import lombok.Getter;
import lombok.Setter;
import org.springframework.boot.context.properties.ConfigurationProperties;
import java.time.Duration;@Getter
@Setter
@ConfigurationProperties(prefix = "sftp")
public class SftpProperties {/*** 主機IP*/private String host = "127.0.0.1";/*** 主機端口,默認22*/private int port = 22;/*** 用戶名*/private String username = "";/*** 登錄密碼*/private String password = "";/*** 連接超時(ms),默認5000ms*/private Duration connectTimeout = Duration.ofMillis(5000);/*** 認證超時(ms),默認10000ms*/private Duration authTimeout = Duration.ofMillis(10000);
}
import org.apache.sshd.client.SshClient;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;@ConditionalOnClass(SshClient.class)
@Configuration
@EnableConfigurationProperties(SftpProperties.class)
public class SshClientConfiguration {@BeanSshClientService sshClientService(SftpProperties properties) {return new SshClientService(SshClient.setUpDefaultClient(), properties);}
}
sftp:host: 127.0.0.1port: 22username: demopassword: pwdconnect-timeout: 5sauth-timeout: 5s

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/913108.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/913108.shtml
英文地址,請注明出處:http://en.pswp.cn/news/913108.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Excel 如何讓數據自動按要求排序或篩選?

讓數據按要求排序和篩選是Excel數據處理的基礎核心功能&#xff0c;也是進行有效分析前必做的準備工作。下面我們分開講解這兩個功能。 一、排序 (Sort)&#xff1a;讓數據井井有條 排序的目的是重新排列數據行的順序&#xff0c;以便更好地觀察和比較。 1. 快速單列排序 (最…

Django 安裝使用教程

一、Django 簡介 Django 是一個高級 Python Web 框架&#xff0c;鼓勵快速開發和簡潔實用的設計。它內置 ORM、認證系統、后臺管理、表單處理、路由控制等功能&#xff0c;廣泛用于開發企業級網站、內容管理系統、電商平臺等。 二、環境準備 2.1 安裝 Python Django 基于 Py…

前沿交叉:Fluent與深度學習驅動的流體力學計算體系

基礎模塊 流體力學方程求解 1、不可壓縮N-S方程數值解法&#xff08;有限差分/有限元/偽譜法&#xff09; Fluent工業級應用&#xff1a;穩態/瞬態流、兩相流仿真&#xff08;圓柱繞流、入水問題&#xff09; Tecplot流場可視化與數據導出 2、CFD數據的AI預處理 基于P…

五、Flutter動畫

目錄1. Flutter 中動畫的基本概念是什么&#xff1f;2. 解釋 AnimationController 和 Tween 的作用3. 如何實現一個補間&#xff08;Tween&#xff09;動畫&#xff1f;4. 什么是隱式動畫&#xff1f;舉例說明5. 如何實現自定義復雜動畫&#xff1f;1. Flutter 中動畫的基本概念…

全網唯一/Qt結合ffmpeg實現手機端采集攝像頭推流到rtsp或rtmp/可切換前置后置攝像頭/指定分辨率幀率

一、前言說明 之前已經實現了Qt結合ffmpeg在安卓上運行&#xff0c;所有在win上的功能&#xff0c;在安卓上都已經實現&#xff0c;比如編碼保存到MP4文件&#xff0c;正常解碼音視頻文件播放等&#xff0c;唯獨還差一個功能&#xff0c;盡管用的不多&#xff0c;但是還是有一…

Install Ubuntu 24.04 System

1.制作安裝鏡像盤&#xff08;U盤&#xff09; 下載rufus制作工具(網址&#xff1a;https://www.xiaomoxz.com/nexus/bi1/rufus4.shtml?bd_vid8643969197265870719&#xff09; 2. 設置U盤啟動&#xff1a; F2進入BIOS 3. Install Ubuntu 24.04 Ubuntu下載地址&#xff1a;…

solidjs 處理復雜類型的響應式

solidjs 處理復雜類型的響應式 在 solidjs 里響應式一般直接用 createSignal 就可以&#xff0c;但 createSignal 一般用于基礎數據類型。 雖然復雜類型也是可以使用&#xff0c;但基于起細粒度響應性的特性。 一般復雜的數據使用 createSignal 就不是那么友好了。 所以 cre…

爬蟲技術-獲取瀏覽器身份認證信息(如 Cookie、Token、Session 等)

方法一&#xff1a;通過瀏覽器開發者工具查看和提取 Cookie / Token &#x1f4cc; 示例場景&#xff1a; 你在使用一個網站時已經登錄了&#xff0c;想看看這個網站是如何保存你的身份憑證的。 &#x1f527; 操作過程&#xff1a; 打開瀏覽器&#xff08;例如 Chrome&#xf…

[密碼學實戰]GMT 0136-2024《密碼應用HTTP接口規范》解析

[密碼學實戰]GM/T 0136-2024《密碼應用HTTP接口規范》解析國家密碼管理局于2025年7月1日正式實施GM/T 0136-2024標準&#xff0c;該規范首次統一了密碼服務的HTTP接口設計&#xff0c;為國產密碼技術的規模化應用鋪平道路。本文結合標準原文&#xff0c;深入剖析其技術細節并給…

Docker 國內鏡像列表(免費長期)

Docker 可用鏡像源列表&#xff08;7月1日更新-長期維護&#xff09;_dockerhub國內鏡像源列表-CSDN博客

BlenderFBXExporter 導出fbx被修改問題

1&#xff09; 解決增加A節點的問題 https://github.com/A-Ribeiro/CustomBlenderFBXExporter 2&#xff09;找出blendshape 不一致&#xff0c;生成blendshape key name映射map 文件compare.txt C:\Users\49938\Documents\DazToUnreal\zhang01\UpdatedFBX\zhang01_fix7.fbx…

AI時代下的IT服務管理轉型:趨勢、挑戰與破局之道

近年來&#xff0c;人工智能&#xff08;AI&#xff09;與自動化技術的迅猛發展&#xff0c;正以前所未有的速度重塑企業運營的各個層面。特別是在IT服務管理&#xff08;ITSM&#xff09;領域&#xff0c;AI的介入不僅提高了問題響應效率&#xff0c;也推動了組織從“被動響應…

三體融合實戰:Django+訊飛星火+Colossal-AI的企業級AI系統架構

目錄 技術棧關鍵詞&#xff1a;Django 5.0 訊飛星火4.0Ultra Colossal-AI 1.2 WebSocket 聯邦學習 ? 核心架構設計 &#x1f6e0;? 一、Django深度集成訊飛星火API&#xff08;免費版&#xff09; 1. 獲取API憑證 2. 流式通信改造&#xff08;解決高并發阻塞&#xff09…

多模態數據融合預警:從IoT傳感器到衛星監測的可視化方案升級

你有沒有想過&#xff0c;為什么有些城市在暴雨來臨時能提前數小時發布內澇預警&#xff0c;而有些地方卻只能“等水來了才反應”&#xff1f; 背后的關鍵&#xff0c;就是多模態數據融合預警系統——它把來自IoT傳感器、無人機、地面雷達、氣象站、甚至衛星的數據整合在一起&a…

面試八股---css

2、css 2.1 說說你對盒子模型的理解 是什么 當對一個文檔進行布局&#xff08;layout&#xff09;的時候&#xff0c;瀏覽器的渲染引擎會根據標準之一的 CSS 基礎框盒模型&#xff08;CSS basic box model&#xff09;&#xff0c;將所有元素表示為一個個矩形的盒子&#xf…

day52-硬件學習之RTC及ADC

一、RTCRTC&#xff08;實時時鐘&#xff09;&#xff1a;非易失性在IMX6ULL內部SNVS&#xff08;安全的非易失性存儲器&#xff09;提供RTC功能&#xff1b;原理圖&#xff1a;二、ADC 2.1 基本概念ADC(模擬數字轉換器)&#xff1a;用于將連續變化的模擬信號轉換為離散的數字信…

Web 項目如何自動化測試?

Web 項目的自動化測試可以通過 UI自動化 和 接口自動化 結合實現&#xff0c;提高測試效率和覆蓋率。以下是關鍵方法和工具&#xff1a; 【自動化測試】從基礎到實戰基于Pytest自動化/python自動化的詳細教程&#xff01;1. UI自動化測試&#xff08;前端交互&#xff09; 適用…

Java連接阿里云MaxCompute例

要使用Java連接阿里云MaxCompute&#xff08;原名ODPS&#xff09;數據庫&#xff0c;您可以遵循以下步驟進行配置和編程&#xff1a; 1. 添加依賴 確保您的項目中包含了MaxCompute JDBC驅動的依賴。如果您使用Maven&#xff0c;可以在pom.xml中添加如下依賴&#xff1a; &l…

【網絡與系統安全】強制訪問控制——BLP模型

一、模型背景與定義 BLP&#xff08;Bell-LaPadula&#xff09;模型是由David Bell和Len Adula在1973年提出的強制訪問控制&#xff08;MAC&#xff09;模型&#xff0c;是最早的計算機安全模型之一&#xff0c;主要用于解決多用戶系統中的信息機密性保護問題&#xff0c;尤其…

HTTPS詳解:原理 + 加解密過程 + 面試問答

一、HTTP 與 HTTPS 的區別 項目HTTPHTTPS全稱HyperText Transfer ProtocolHyperText Transfer Protocol Secure端口80443協議層應用層應用層 TLS&#xff08;安全層&#xff09;加密方式明文傳輸加密傳輸&#xff08;TLS&#xff09;安全性易被劫持、中間人攻擊可加密、防篡改…