WebSSH技术实现全解析

WebSSH 项目技术实现详解

一、项目概述

本项目实现了一个功能完善的 WebSSH 终端系统,允许用户通过浏览器安全地访问远程 Linux 服务器。系统采用前后端分离架构,前端使用 Vue 3 + xterm.js 实现终端界面,后端使用 Spring Boot + SSHJ 实现 SSH 连接管理。


二、技术架构

2.1 整体架构

复制代码
┌─────────────────────────────────────────────────────────────────┐
│                         前端层 (Vue 3)                          │
│  ┌──────────────────┐  ┌──────────────────┐                     │
│  │   Terminal UI    │  │   Server List    │                     │
│  │  (xterm.js)      │  │   (Element Plus) │                     │
│  └────────┬─────────┘  └────────┬─────────┘                     │
│           │                     │                               │
│           └─────────┬───────────┘                               │
│                     │ WebSocket (STOMP)                         │
├─────────────────────┼───────────────────────────────────────────┤
│                         后端层 (Spring Boot)                    │
│  ┌───────────────────────────────────────────────────────────┐  │
│  │              SshController (WebSocket Handler)            │  │
│  │  ┌───────────────────────────────────────────────────┐   │  │
│  │  │              SSHManager (SSHJ Connection Pool)    │   │  │
│  │  │  ┌─────────┐ ┌─────────┐ ┌─────────┐             │   │  │
│  │  │  │ Server1 │ │ Server2 │ │ Server3 │ ...          │   │  │
│  │  │  └────┬────┘ └────┬────┘ └────┬────┘             │   │  │
│  │  └───────┴───────────┴───────────┴───────────────────┘   │  │
│  └───────────────────────────────────────────────────────────┘  │
├─────────────────────────────────────────────────────────────────┤
│                        远程服务器层                              │
│  ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐    │
│  │   Linux Server  │ │   Linux Server  │ │   Linux Server  │    │
│  └─────────────────┘ └─────────────────┘ └─────────────────┘    │
└─────────────────────────────────────────────────────────────────┘

2.2 技术栈

层次 技术 版本 说明
前端框架 Vue 3.x 渐进式 JavaScript 框架
终端组件 xterm.js 5.x 功能强大的终端模拟器
UI 组件库 Element Plus 2.x Vue 3 组件库
通信协议 STOMP over WebSocket - 消息队列协议
后端框架 Spring Boot 3.x Java 微服务框架
SSH 客户端 SSHJ 0.37.x Java SSH 库
数据库 MySQL/DM6 - 服务器配置存储

三、后端实现

3.1 SSH 连接管理器 (SSHManager)

核心类 SSHManager 负责管理 SSH 连接的生命周期,支持密码和私钥两种认证方式。

关键设计要点:

  1. 连接池机制 :使用 ConcurrentHashMap 实现连接复用,避免频繁创建连接
java 复制代码
private static final Map<Long, SSHManager> connectionPool = new ConcurrentHashMap<>();
  1. 双认证支持:同时支持密码认证和私钥认证
java 复制代码
if (privateKey != null && !privateKey.isEmpty()) {
    // 私钥认证
    OpenSSHKeyFile keyFile = new OpenSSHKeyFile();
    keyFile.init(new StringReader(privateKey));
    sshClient.authPublickey(username, keyFile);
} else {
    // 密码认证
    sshClient.authPassword(username, password);
}
  1. Shell 会话管理:独立的 Shell 会话,支持终端大小调整
java 复制代码
public void startShell() throws Exception {
    session = sshClient.startSession();
    session.allocateDefaultPTY();
    shell = session.startShell();
    inputStream = shell.getInputStream();
    outputStream = shell.getOutputStream();
}
  1. SFTP 复用:同一个 SSH 连接可同时支持 Shell 和 SFTP 会话
java 复制代码
public SFTPClient getSftpClient() throws IOException {
    if (sftpClient == null) {
        if (!isConnected()) {
            throw new IOException("SSH连接已断开");
        }
        sftpClient = sshClient.newSFTPClient();
    }
    return sftpClient;
}

3.2 WebSocket 控制器 (SshController)

使用 Spring WebSocket + STOMP 协议实现实时通信。

消息端点设计:

端点 方法 功能
/app/terminal/init/{sessionId} initTerminal 初始化 SSH 连接
/app/terminal/data/{sessionId} sendData 发送命令数据
/app/terminal/resize/{sessionId} resizeTerminal 调整终端大小
/app/terminal/charset/{sessionId} changeCharset 切换字符编码
/app/terminal/disconnect/{sessionId} disconnectTerminal 断开连接

消息处理流程:

java 复制代码
@MessageMapping("/terminal/init/{sessionId}")
public void initTerminal(@DestinationVariable String sessionId, 
                         @Payload String messageJson, 
                         SimpMessageHeaderAccessor headerAccessor) {
    // 1. 解析服务器配置
    JsonNode jsonNode = objectMapper.readTree(messageJson);
    String serverId = jsonNode.get("serverId").asText();
    
    // 2. 获取服务器信息
    SshServer server = sshServerService.getById(serverId);
    
    // 3. 创建/复用 SSH 连接
    SSHManager sshManager = SSHManager.getOrCreateConnection(server, true);
    sshManager.startShell();
    sessionMap.put(sessionId, sshManager);
    
    // 4. 设置输出处理器,将 SSH 输出转发给前端
    sshManager.setOutputHandler(data -> {
        messagingTemplate.convertAndSendToUser(userId, "/queue/terminal", dataMap);
    });
}

3.3 连接池策略

java 复制代码
public static SSHManager getOrCreateConnection(SshServer server, boolean forceNew) {
    Long serverId = Long.valueOf(server.getId());
    
    // 强制新建:先清理池中旧连接
    if (forceNew) {
        SSHManager old = connectionPool.remove(serverId);
        if (old != null) {
            old.disconnect();
        }
    } else {
        // 尝试复用池中连接
        SSHManager manager = connectionPool.get(serverId);
        if (manager != null && manager.isConnected()) {
            return manager;
        }
    }
    
    // 创建新连接并加入连接池
    SSHManager manager = fromServer(server);
    connectionPool.put(serverId, manager);
    return manager;
}

四、前端实现

4.1 终端组件初始化

使用 xterm.js 创建终端实例,支持多种主题和自定义配置。

javascript 复制代码
const initTerminal = async () => {
    const { Terminal } = await import('@xterm/xterm')
    const { FitAddon } = await import('@xterm/addon-fit')
    
    terminal = new Terminal({
        cursorBlink: true,
        cursorStyle: 'block',
        fontSize: 18,
        fontFamily: '"Fira Code", monospace',
        theme: {
            background: '#282a36',
            foreground: '#f8f8f2'
        },
        scrollback: 10000,
        lineWrap: true
    })
    
    fitAddon = new FitAddon()
    terminal.loadAddon(fitAddon)
    terminal.open(terminalRef.value)
    
    // 监听用户输入
    terminal.onData(data => {
        if (isConnected()) {
            sendMessage('/app/terminal/data/' + sessionId, {}, JSON.stringify({ data }))
        }
    })
}

4.2 WebSocket 连接管理

封装 STOMP 客户端,处理连接建立和消息订阅。

javascript 复制代码
const connect = async () => {
    // 1. 建立 WebSocket 连接
    await StompServerConnect()
    
    // 2. 生成唯一会话 ID
    sessionId = 'ssh-' + Date.now()
    const userId = 'user-' + sessionId
    
    // 3. 订阅终端消息
    const stompClient = getStompClient()
    sshSubscription = stompClient.subscribe(
        '/user/' + userId + '/queue/terminal', 
        (message) => {
            const msg = JSON.parse(message.body)
            if (msg.type === 'data') {
                terminal.write(msg.data)
            }
        }
    )
    
    // 4. 初始化 SSH 会话
    await sendMessage('/app/terminal/init/' + sessionId, { 'userId': userId }, 
        JSON.stringify({
            serverId: selectedServer.value.id,
            cols: terminal.cols,
            rows: terminal.rows,
            charset: 'UTF-8'
        }))
}

4.3 多面板布局

实现可拖拽的分屏布局,支持同时显示终端、SFTP、监控和 Docker 面板。

vue 复制代码
<el-splitter :model-value="splitPosition" class="ssh-splitter">
    <!-- 左侧服务器列表 -->
    <el-splitter-panel :size="splitPosition">
        <div class="server-panel">...</div>
    </el-splitter-panel>
    
    <!-- 右侧终端区域 -->
    <el-splitter-panel>
        <el-splitter class="right-splitter">
            <!-- 主终端 -->
            <el-splitter-panel>
                <div class="terminal-panel">...</div>
            </el-splitter-panel>
            
            <!-- SFTP 面板 -->
            <el-splitter-panel v-if="showSftpPanel">
                <SftpPanel />
            </el-splitter-panel>
        </el-splitter>
    </el-splitter-panel>
</el-splitter>

五、核心功能

5.1 服务器管理

支持服务器的增删改查,支持密码和密钥两种认证方式。

服务器配置实体:

字段 类型 说明
id Long 主键
serverName String 服务器名称
host String 主机地址
port Integer SSH 端口
username String 用户名
password String 密码(加密存储)
privateKey String 私钥内容
authType String 认证类型 (password/key)
remark String 备注

5.2 终端设置

支持丰富的终端个性化配置:

  • 字体设置:字号、字体样式
  • 光标设置:样式(方块/下划线/竖线)、闪烁
  • 滚动设置:缓冲区行数
  • 主题设置:深空蓝、黑客绿、VS Code Dark、Monokai、Solarized Dark、Dracula
  • 编码设置:UTF-8、GBK、GB2312、Latin-1

5.3 安全特性

  1. 危险命令检测:执行命令前进行安全检测
javascript 复制代码
const handleExecuteCommand = async (cmd) => {
    const res = await securityCheck(cmd.commandContent)
    if (res.code !== 200) {
        securityWarningMessage.value = res.message
        showSecurityWarning.value = true
        return
    }
    executeCommandDirectly(cmd)
}
  1. 连接超时处理:设置合理的连接超时时间,避免资源泄漏
java 复制代码
private static final int CONNECT_TIMEOUT = 60000;
sshClient.setConnectTimeout(CONNECT_TIMEOUT);
  1. 连接状态监控:实时检测连接状态,自动重连

六、性能优化

6.1 连接复用

通过连接池复用 SSH 连接,减少连接建立开销。

6.2 防抖处理

对终端 resize 事件进行防抖处理,避免频繁发送 resize 请求。

javascript 复制代码
const debounce = (func, wait) => {
    let timeout
    return function (...args) {
        clearTimeout(timeout)
        timeout = setTimeout(() => func.apply(this, args), wait)
    }
}

const handleResizeDebounced = debounce((size) => {
    if (isConnected() && size.cols > 0 && size.rows > 0) {
        sendMessage('/app/terminal/resize/' + sessionId, {}, JSON.stringify(size))
    }
}, 200)

6.3 懒加载

按需加载 xterm.js 组件,减少首屏加载时间。

javascript 复制代码
const { Terminal } = await import('@xterm/xterm')

七、使用示例

7.1 添加服务器

javascript 复制代码
const addServer = async () => {
    const res = await addSshServer({
        serverName: '生产服务器',
        host: '192.168.1.100',
        port: 22,
        username: 'root',
        password: '******',
        authType: 'password',
        remark: '生产环境主服务器'
    })
}

7.2 连接服务器

javascript 复制代码
// 选择服务器
selectedServer.value = serverList.value[0]

// 初始化终端
await initTerminal()

// 建立连接
await connect()

八、总结

本 WebSSH 项目实现了一个功能完整、性能优秀的远程终端系统,具备以下特点:

  1. 高可用性:连接池机制确保连接复用和故障恢复
  2. 安全性:危险命令检测、连接超时保护
  3. 用户体验:丰富的主题配置、流畅的终端交互
  4. 扩展性:模块化设计,易于添加新功能

项目架构清晰,代码结构合理,是企业级 WebSSH 解决方案的理想选择。


项目文件结构:

复制代码
server/src/main/java/com/kd/ssh/
├── config/
│   └── SSHManager.java          # SSH 连接管理器
├── controller/
│   ├── SshController.java       # WebSocket 控制器
│   ├── SftpController.java      # SFTP 控制器
│   └── DockerController.java    # Docker 控制器
├── entity/
│   └── SshServer.java           # 服务器实体
├── mapper/
│   └── SshServerMapper.java     # 数据库操作
└── service/
    └── SshServerService.java    # 业务服务

ui/src/views/ssh/
├── index.vue                    # 主页面
├── ssh.js                       # WebSocket 封装
└── components/
    ├── SftpPanel.vue            # SFTP 面板
    ├── QuickCommandPanel.vue    # 快捷命令面板
    ├── ServerMonitorPanel.vue   # 服务器监控面板
    └── DockerPanel.vue          # Docker 面板
相关推荐
暗冰ཏོ1 小时前
运维岗位完整学习指南:从 Linux 基础到 DevOps / SRE 实战
linux·运维·服务器·ubuntu·运维开发·devops
龙泉寺天下行走1 小时前
bash (())奇怪的返回码
linux·运维·服务器
Fcy6481 小时前
Linux下 进程间通信详解(二)System V IPC
linux·运维·消息队列·共享内存·信号量·system v
vortex51 小时前
SSH “administratively prohibited” 报错解决
运维·ssh
皆圥忈2 小时前
Linux文件系统与缓冲区深度解析
linux
Dream_ksw2 小时前
借助AI再次理解三次握手和四次挥手
服务器·网络·tcp/ip
壹号用户2 小时前
初识linux
linux·运维·服务器
衫水2 小时前
Windows Server Nginx 代理企业内网 API 偶发超时处理与保活 SOP(20260608))
运维·windows·nginx
Java 码思客2 小时前
【Redis分布式缓存实战】第20章 Redis监控运维与自动化体系
运维·redis·缓存