Python脚本SFTP连接如何免密登录

wen 实用脚本 4

本文目录导读:

Python脚本SFTP连接如何免密登录

  1. 使用SSH Agent
  2. 使用Agent中的密钥
  3. 开启调试日志

要实现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()

安全注意事项

  1. 密钥权限:确保SSH密钥文件的权限正确

    chmod 600 ~/.ssh/id_rsa
    chmod 644 ~/.ssh/id_rsa.pub
    chmod 700 ~/.ssh
  2. 使用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
  1. 调试连接
    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。

抱歉,评论功能暂时关闭!