本文目录导读:

要实现Python脚本SFTP免密登录,主要有两种方法:SSH密钥认证 和 使用ssh配置文件,最常用和推荐的是SSH密钥认证方式。
SSH密钥认证(推荐)
生成SSH密钥对
# 在本地生成RSA密钥对 ssh-keygen -t rsa -b 4096 -f ~/.ssh/id_rsa -N ""
将公钥上传到服务器
# 方式1:使用ssh-copy-id ssh-copy-id username@remote_host # 方式2:手动复制 cat ~/.ssh/id_rsa.pub | ssh username@remote_host "mkdir -p ~/.ssh && cat >> ~/.ssh/authorized_keys"
使用Paramiko实现免密登录
import paramiko
def sftp_with_key(host, port, username, key_file=None):
"""
使用SSH密钥进行SFTP连接
"""
try:
# 创建SSH客户端
ssh = paramiko.SSHClient()
# 自动添加未知主机密钥
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
# 方法1:使用默认密钥文件(~/.ssh/id_rsa)
if key_file is None:
ssh.connect(
hostname=host,
port=port,
username=username
)
# 方法2:指定密钥文件路径
else:
private_key = paramiko.RSAKey.from_private_key_file(key_file)
ssh.connect(
hostname=host,
port=port,
username=username,
pkey=private_key
)
# 创建SFTP客户端
sftp = ssh.open_sftp()
print("SFTP连接成功!")
# 示例操作
sftp.chdir('/remote/path') # 切换目录
files = sftp.listdir() # 列出文件
print(f"远程目录文件: {files}")
# 上传文件示例
# sftp.put('local_file.txt', 'remote_file.txt')
# 下载文件示例
# sftp.get('remote_file.txt', 'local_file.txt')
# 关闭连接
sftp.close()
ssh.close()
return True
except Exception as e:
print(f"连接失败: {str(e)}")
return False
# 使用示例
if __name__ == "__main__":
# 使用默认密钥
sftp_with_key(
host="192.168.1.100",
port=22,
username="your_username"
)
# 或指定密钥文件
# sftp_with_key(
# host="192.168.1.100",
# port=22,
# username="your_username",
# key_file="/path/to/id_rsa"
# )
更完善的封装版本
import paramiko
import os
from typing import Optional, List
class SFTPManager:
"""SFTP连接管理器"""
def __init__(self, host: str, port: int = 22, username: str = None,
key_file: str = None, password: str = None):
self.host = host
self.port = port
self.username = username
self.key_file = key_file or os.path.expanduser("~/.ssh/id_rsa")
self.password = password
self.ssh = None
self.sftp = None
def connect(self) -> bool:
"""建立SFTP连接"""
try:
self.ssh = paramiko.SSHClient()
self.ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
# 优先使用密钥认证
if os.path.exists(self.key_file):
try:
private_key = paramiko.RSAKey.from_private_key_file(self.key_file)
self.ssh.connect(
hostname=self.host,
port=self.port,
username=self.username,
pkey=private_key
)
except:
# 密钥认证失败,尝试密码认证
if self.password:
self.ssh.connect(
hostname=self.host,
port=self.port,
username=self.username,
password=self.password
)
else:
raise
elif self.password:
self.ssh.connect(
hostname=self.host,
port=self.port,
username=self.username,
password=self.password
)
else:
raise Exception("未提供认证方式(密钥或密码)")
self.sftp = self.ssh.open_sftp()
return True
except Exception as e:
print(f"连接失败: {e}")
return False
def disconnect(self):
"""断开连接"""
if self.sftp:
self.sftp.close()
if self.ssh:
self.ssh.close()
def upload_file(self, local_path: str, remote_path: str) -> bool:
"""上传文件"""
try:
self.sftp.put(local_path, remote_path)
return True
except Exception as e:
print(f"上传失败: {e}")
return False
def download_file(self, remote_path: str, local_path: str) -> bool:
"""下载文件"""
try:
self.sftp.get(remote_path, local_path)
return True
except Exception as e:
print(f"下载失败: {e}")
return False
def list_files(self, remote_path: str = ".") -> List[str]:
"""列出目录文件"""
try:
return self.sftp.listdir(remote_path)
except Exception as e:
print(f"列出文件失败: {e}")
return []
# 使用示例
if __name__ == "__main__":
# 创建SFTP管理器
sftp_mgr = SFTPManager(
host="192.168.1.100",
port=22,
username="user",
key_file="~/.ssh/id_rsa" # 可选,默认使用此路径
)
# 连接
if sftp_mgr.connect():
print("连接成功!")
# 执行操作
files = sftp_mgr.list_files("/remote/path")
print(f"文件列表: {files}")
# 上传文件
# sftp_mgr.upload_file("local.txt", "/remote/path/remote.txt")
# 下载文件
# sftp_mgr.download_file("/remote/path/file.txt", "local_file.txt")
# 断开连接
sftp_mgr.disconnect()
使用fabric库(更高级的封装)
from fabric import Connection
def fabric_sftp_example():
"""使用fabric库进行免密SFTP"""
# 方法1:使用默认密钥
c = Connection(
host="192.168.1.100",
user="username",
connect_kwargs={
"key_filename": "~/.ssh/id_rsa" # 指定密钥文件
}
)
# 方法2:使用ssh配置文件
# c = Connection("username@192.168.1.100")
# 上传文件
c.put("local_file.txt", "/remote/path/")
# 下载文件
c.get("/remote/path/remote_file.txt", "local/")
# 执行远程命令
result = c.run("ls -la")
print(result.stdout)
c.close()
安全注意事项
-
密钥权限:确保SSH密钥文件的权限正确
chmod 600 ~/.ssh/id_rsa chmod 644 ~/.ssh/id_rsa.pub chmod 700 ~/.ssh
-
使用SSH Agent(避免密钥密码反复输入):
import paramiko import os
使用SSH Agent
agent = paramiko.Agent() agent_keys = agent.get_keys()
ssh = paramiko.SSHClient() ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
使用Agent中的密钥
ssh.connect( hostname="192.168.1.100", username="user", look_for_keys=True # 自动查找SSH Agent中的密钥 )
## 常见问题排查
1. **检查服务器端配置**:确保服务器的SSH配置允许密钥认证
```bash
# 在远程服务器上检查
sudo grep "PubkeyAuthentication" /etc/ssh/sshd_config
# 应该显示: PubkeyAuthentication yes
- 调试连接:
import paramiko import logging
开启调试日志
logging.basicConfig(level=logging.DEBUG) paramiko.util.log_to_file('paramiko.log')
3. **测试连接**:
```bash
ssh -v username@remote_host
选择哪种方法取决于你的具体需求,对于简单的脚本,直接用Paramiko就足够了;如果需要更复杂的运维操作,可以考虑使用Fabric。