Dart SSH
最后修改日期:2024 年 1 月 28 日
本文介绍如何使用 Dart 语言操作 SSH 和 SFTP。我们使用 DartSSH 2 库。
安全外壳协议 (SSH) 是一种在两个网络主机之间创建加密通道的协议。 安全文件传输协议 (SFTP) 是一种用于安全访问、传输和管理文件的网络协议。它运行在 SSH 之上。
SSH 身份验证主要有两种方式,用于安全的远程访问:
- 密码验证(用户名和密码)
- 公钥身份验证(公钥和私钥对)
DartSSH 2 库提供了一个用纯 Dart 编写的 SSH 和 SFTP 客户端。它允许创建 SSH 会话、提供身份验证和转发。它支持 SFTPv3 协议的所有功能,包括上传、下载、删除、重命名或移除。
$ dart pub add dartssh2
Dart SSH 执行命令
在下一个示例中,我们将远程执行一个命令。
import 'dart:convert';
import 'dart:io';
import 'package:dartssh2/dartssh2.dart';
void main() async {
final ip = "192.168.0.25";
final username = "user7";
final socket = await SSHSocket.connect(ip, 22);
final client = SSHClient(
socket,
username: username,
onPasswordRequest: () {
stdout.write('Password: ');
stdin.echoMode = false;
return stdin.readLineSync() ?? exit(1);
},
);
final res = await client.run('uname -a');
print("\n");
print(utf8.decode(res));
client.close();
await client.done;
}
我们连接到本地网络中的一台计算机并运行 uname 命令。
import 'package:dartssh2/dartssh2.dart';
我们导入 dartssh2 库。
final socket = await SSHSocket.connect(ip, 22);
使用 SSHSocket.connect 创建一个套接字。
final client = SSHClient(
socket,
username: username,
onPasswordRequest: () {
stdout.write('Password: ');
stdin.echoMode = false;
return stdin.readLineSync() ?? exit(1);
},
);
使用该套接字,我们创建一个 SSH 客户端。连接后,客户端会要求输入密码。密码不会显示出来。
final res = await client.run('uname -a');
我们运行 uname 命令。
print(utf8.decode(res));
我们打印解码后的响应。
client.close();
使用 close 终止连接。
await client.done;
我们等待传输关闭。
$ dart main.dart Password: Linux debian 4.19.0-23-amd64 #1 SMP Debian 4.19.269-1 ...
Dart SSH shell
使用 shell 函数,我们可以创建一个交互式 shell 会话。
import 'dart:io';
import 'dart:typed_data';
import 'package:dartssh2/dartssh2.dart';
void main() async {
final ip = "192.168.0.25";
final username = "user7";
final socket = await SSHSocket.connect(ip, 22);
final client = SSHClient(
socket,
username: username,
onPasswordRequest: () {
stdout.write('Password: ');
stdin.echoMode = false;
return stdin.readLineSync() ?? exit(1);
},
);
final shell = await client.shell();
stdin.echoMode = true;
stdout.addStream(shell.stdout);
stderr.addStream(shell.stderr);
stdin.cast<Uint8List>().listen(shell.write);
await shell.done;
client.close();
await client.done;
exit(0);
}
程序创建一个交互式 shell 会话。
final shell = await client.shell(); stdin.echoMode = true;
我们创建一个 shell 会话并开启回显模式,以便我们可以看到我们输入的内容。
stdout.addStream(shell.stdout); stderr.addStream(shell.stderr); stdin.cast<Uint8List>().listen(shell.write);
我们将远程标准流连接到我们的本地流。
await shell.done;
我们等待 shell 终止。我们可以使用 exit 命令终止 shell。
Dart SSH 公钥身份验证
在下一个示例中,我们将使用更安全的公钥身份验证方式进行身份验证。
import 'dart:convert';
import 'dart:io';
import 'package:dartssh2/dartssh2.dart';
void main() async {
final ip = "192.168.0.25";
final username = "user7";
final rsa_key = "C:\\Users\\Jano\\.ssh\\id_rsa";
final socket = await SSHSocket.connect(ip, 22);
final client = SSHClient(
socket,
username: username,
identities: [
...SSHKeyPair.fromPem(await File(rsa_key).readAsString(), 'passphrase')
],
);
final uptime = await client.run('uptime');
print(utf8.decode(uptime));
client.close();
await client.done;
}
程序连接到远程系统,使用公钥身份验证进行身份验证,并执行 uptime 命令。
final rsa_key = "C:\\Users\\Jano\\.ssh\\id_rsa";
这是我们 Windows 操作系统上 RSA 私钥的位置。
final client = SSHClient(
socket,
username: username,
identities: [
...SSHKeyPair.fromPem(await File(rsa_key).readAsString(), 'passphrase')
],
);
我们将私钥传递给 SSHKeyPair.fromPem 函数。密钥也可能受密码保护。另外请注意,远程系统必须在 ~/.ssh/authorized_keys 文件中包含我们的公钥。
final uptime = await client.run('uptime');
print(utf8.decode(uptime));
我们运行命令并打印解码后的响应。
$ dart main.dart 06:45:06 up 30 min, 1 user, load average: 0.00, 0.00, 0.00
Dart SFTP 列出目录
在下面的示例中,我们将通过 SFTP 列出目录内容。
import 'dart:io';
import 'package:dartssh2/dartssh2.dart';
void main(List<String> args) async {
final ip = "93.184.216.34";
final username = "user7";
final dirname = args.first;
final socket = await SSHSocket.connect(ip, 22);
final client = SSHClient(
socket,
username: username,
onPasswordRequest: () {
stdout.write('Password: ');
stdin.echoMode = false;
return stdin.readLineSync() ?? exit(1);
},
);
final sftp = await client.sftp();
final items = await sftp.listdir(dirname);
print("\n");
for (final item in items) {
print(item.longname);
}
client.close();
await client.done;
}
程序接受一个参数,该参数是目录的路径,例如 /web/perl/。
final dirname = args.first;
我们获取第一个命令行参数。预期它是远程目录的路径。
final sftp = await client.sftp(); final items = await sftp.listdir(dirname);
使用 sftp 函数创建一个 SFTP 客户端。使用 listdir 检索目录列表。
for (final item in items) {
print(item.longname);
}
我们遍历路径名列表并打印它们。
$ dart main.dart /web/perl Password: drwx---r-x 12 user7 117992 12 Jan 23 20:00 . drwx------ 56 user7 117992 61 Jan 11 16:39 .. drwx---r-x 2 user7 117992 3 Jan 4 12:31 string2 drwx---r-x 2 user7 117992 3 Jan 4 12:31 dbi drwx---r-x 2 user7 117992 3 Jan 4 12:31 string drwx---r-x 2 user7 117992 3 Jan 4 12:31 hash drwxr-xr-x 2 user7 117992 3 Jan 19 13:39 read-file drwxr-xr-x 2 user7 117992 3 Jan 23 20:00 loops drwxr-xr-x 2 user7 117992 3 Jan 4 12:31 grep drwx---r-x 2 user7 117992 3 Jan 4 12:31 array drwx---r-x 2 user7 117992 3 Jan 4 12:31 socket drwx---r-x 2 user7 117992 3 Jan 4 12:31 lwp
Dart SFTP 创建目录
mkdir 用于创建一个新目录。
import 'dart:io';
import 'package:dartssh2/dartssh2.dart';
void main(List<String> args) async {
final ip = "93.184.216.34";
final username = "user7";
final dirname = args.first;
final socket = await SSHSocket.connect(ip, 22);
final client = SSHClient(
socket,
username: username,
onPasswordRequest: () {
stdout.write('Password: ');
stdin.echoMode = false;
return stdin.readLineSync() ?? exit(1);
},
);
final sftp = await client.sftp();
await sftp.mkdir(dirname);
print('directory created');
client.close();
await client.done;
}
程序在远程系统上创建一个新目录。目录名称作为第一个命令行参数传递。
Dart SFTP 上传文件
open 函数用于打开一个远程文件。
import 'dart:io';
import 'package:dartssh2/dartssh2.dart';
void main(List<String> args) async {
final ip = "93.184.216.34";
final username = "user7";
final lname = args.first;
final rname = args.last;
final socket = await SSHSocket.connect(ip, 22);
final client = SSHClient(
socket,
username: username,
onPasswordRequest: () {
stdout.write('Password: ');
stdin.echoMode = false;
return stdin.readLineSync() ?? exit(1);
},
);
final sftp = await client.sftp();
final file = await sftp.open(
rname,
mode: SftpFileOpenMode.truncate |
SftpFileOpenMode.create |
SftpFileOpenMode.write,
);
await file.write(File(lname).openRead().cast());
print("\n");
print('file successfully uploaded');
client.close();
await client.done;
}
程序将一个文件上传到远程系统。
final lname = args.first; final rname = args.last;
我们有两个命令行参数。第一个是要上传的本地文件名,第二个是远程文件的完整路径。
final file = await sftp.open(
rname,
mode: SftpFileOpenMode.truncate |
SftpFileOpenMode.create |
SftpFileOpenMode.write,
);
我们以写入模式在远程系统上使用 open 打开文件。如果文件存在,则会被截断,如果不存在,则会被创建。
await file.write(File(lname).openRead().cast());
数据从本地文件读取并写入远程文件。
Dart SFTP 下载文件
以下程序用于下载文件。
import 'dart:convert';
import 'dart:io';
import 'package:dartssh2/dartssh2.dart';
void main(List<String> args) async {
final ip = "93.184.216.34";
final username = "user7";
final rname = args.first;
final lname = args.last;
final socket = await SSHSocket.connect(ip, 22);
final client = SSHClient(
socket,
username: username,
onPasswordRequest: () {
stdout.write('Password: ');
stdin.echoMode = false;
return stdin.readLineSync() ?? exit(1);
},
);
final sftp = await client.sftp();
final rfile = await sftp.open(
rname,
mode: SftpFileOpenMode.read,
);
final data = await rfile.readBytes();
final lfile = File(lname).openWrite();
lfile.write(utf8.decode(data));
print('file downloaded');
client.close();
await client.done;
}
程序与上一个类似;我们再次利用 open 函数。
final rname = args.first; final lname = args.last;
程序接受两个参数。第一个是远程文件的完整路径(例如 /web/dart/ssh/index.html),第二个是本地文件名。
final rfile = await sftp.open( rname, mode: SftpFileOpenMode.read, );
我们以读取模式打开远程文件。
final data = await rfile.readBytes();
我们使用 readBytes 读取字节。
final lfile = File(lname).openWrite(); lfile.write(utf8.decode(data));
我们将解码后的数据写入本地文件。
来源
在本文中,我们已使用 Dart 操作了 SSH 和 SFTP。
作者
列出 所有 Dart 教程。