You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用Paramiko搭建SFTP时查询ORM对象遇TypeError编码错误

Paramiko SFTP认证报错TypeError: string argument without an encoding,SQLAlchemy LargeBinary字段实际为character varying

问题描述

用Python的Paramiko搭建SFTP服务器,通过SQLAlchemy连接PostgreSQL存储用户凭证。使用FileZilla/WinSCP密码登录时,authenticate_user函数触发TypeError: string argument without an encoding,错误栈指向SQLAlchemy查询结果执行bytes(value)的步骤。

在User类中将password_hash字段定义为LargeBinary类型,但通过SQLAlchemy inspect工具和pgAdmin4检查发现,数据库中该列实际类型为character varying。想明确:

  1. 代码定义与实际列类型不符的原因
  2. 这是否是触发认证错误的根源

相关代码片段

User类定义

from sqlalchemy import Column, Integer, String, LargeBinary
from sqlalchemy.ext.declarative import declarative_base

Base = declarative_base()

class User(Base):
    __tablename__ = 'users'
    id = Column(Integer, primary_key=True)
    username = Column(String(50), unique=True, nullable=False)
    password_hash = Column(LargeBinary, nullable=False)

认证函数

def authenticate_user(username, password):
    from sqlalchemy.orm import sessionmaker
    from your_db_module import engine, User

    Session = sessionmaker(bind=engine)
    session = Session()
    user = session.query(User).filter_by(username=username).first()
    session.close()

    if user:
        import bcrypt
        # 错误触发点
        return bcrypt.checkpw(password.encode('utf-8'), bytes(user.password_hash))
    return False

错误栈

TypeError: string argument without an encoding
Traceback (most recent call last):
  File "/path/to/your/sftp_server.py", line 45, in authenticate_user
    return bcrypt.checkpw(password.encode('utf-8'), bytes(user.password_hash))
TypeError: string argument without an encoding

问题分析与解决

1. LargeBinary变成character varying的原因

  • 表结构未同步:如果在定义User类并执行Base.metadata.create_all(engine)之前,数据库中已存在users表,且password_hash列是character varying类型,SQLAlchemy默认不会修改已存在的表结构(需用Alembic等迁移工具主动同步)。
  • 模型修改后未更新表:修改User类的字段类型后,未重新生成表或执行迁移,导致数据库结构与代码定义脱节。
  • 历史遗留问题:早期版本的模型定义中该字段是String类型,后续修改为LargeBinary但未更新数据库。

2. 字段类型不符是认证错误的根源

是的,原因如下:

  • 数据库中password_hash存储为字符串(character varying),SQLAlchemy查询后返回Python字符串类型。
  • 调用bytes(user.password_hash)时,字符串转bytes必须指定编码(如bytes(str_val, 'utf-8')),未传编码参数会直接触发TypeError。
  • 若字段为正确的LargeBinary类型,SQLAlchemy会直接返回bytes对象,无需额外转换,也就不会报错。

3. 解决步骤

方案一:修正数据库表结构(推荐)

  • 手动在pgAdmin4中将users.password_hash列类型修改为bytea(PostgreSQL对应SQLAlchemy LargeBinary的原生类型)。
  • 生产环境建议用Alembic生成迁移脚本,自动同步表结构,避免数据丢失。

方案二:同步模型与数据库(开发环境)

删除旧表后重新执行表生成命令:

Base.metadata.drop_all(engine)
Base.metadata.create_all(engine)

注意:该操作会清空表数据,仅适用于开发测试环境

方案三:临时兼容(权宜之计)

若暂时无法修改表结构,可临时指定编码转换:

return bcrypt.checkpw(password.encode('utf-8'), bytes(user.password_hash, 'utf-8'))

但这只是临时方案,长期必须保证模型与数据库字段类型一致。

内容的提问来源于stack exchange,提问作者MagoLione

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.17 21:56:09