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

Python验证加密密码时触发TypeError:需bytes类对象而非str

解决登录验证时的TypeError及密码哈希不匹配问题

问题根源

  1. 二进制数据存储/读取格式不兼容:Access数据库存储二进制数据(salt、哈希值)后,通过pyodbc读取时会自动转为十六进制字符串,而hashlib.pbkdf2_hmac要求传入bytes类型参数,因此触发TypeError: a bytes-like object is required, not 'str'。
  2. 哈希计算逻辑不一致:创建用户时计算哈希会将密码与PEPPER拼接后编码,但登录时仅编码了密码,导致最终哈希值与数据库存储的不匹配。

修改后的完整代码

1. 修正用户创建逻辑(确保存储十六进制字符串)

import pyodbc
import os
import hashlib
  
PEPPER = "SECRET_KEY" 
db_path = "你的数据库路径.accdb"  # 请替换为实际路径

def create_user(username, password):
    conn = pyodbc.connect(
            r"Driver={Microsoft Access Driver (*.mdb, *.accdb)};DBQ=" + db_path + ";"
        ) 
    cursor = conn.cursor()
   
    # 生成安全哈希
    password_hash = create_secure_password(password)  

    # 拆分哈希组件并转为十六进制字符串存储
    salt, key = password_hash[:16], password_hash[16:]
    hash_algo = "sha256"
    iterations = 100_000
    salt_hex = salt.hex()
    key_hex = key.hex()

    # 插入数据库
    info = (username, key_hex, salt_hex, hash_algo, iterations)
    cursor.execute("INSERT INTO Login_Info ([username], [password_hash], [salt], [hash_algo], [iterations] ) VALUES (?, ?, ?, ?, ?)", info)

    conn.commit()
    conn.close()

def create_secure_password(password):
    salt = os.urandom(16)  
    iterations = 100_000
    # 密码+PEPPER拼接后编码
    password_input = password.encode('utf-8') + PEPPER.encode('utf-8')
    hash_value = hashlib.pbkdf2_hmac('sha256', password_input, salt, iterations)  
    password_hash = salt + hash_value
    return password_hash 

2. 修正登录验证逻辑(恢复bytes类型+匹配哈希逻辑)

def login(username, password):
    conn = pyodbc.connect(
            r"Driver={Microsoft Access Driver (*.mdb, *.accdb)};DBQ=" + db_path + ";"
        ) 
    cursor = conn.cursor()
 
    select_sql = "SELECT * FROM Login_Info WHERE username = ?"
    cursor.execute(select_sql, (username,))
    account = cursor.fetchone()

    if not account:
        print("Invalid username")
        conn.close()
        return
 
    # 按数据库字段顺序取值:username[0], password_hash[1], salt[2], hash_algo[3], iterations[4]
    db_key_hex, salt_hex, hash_algo, iterations = account[1], account[2], account[3], account[4]

    # 将十六进制字符串转回bytes类型
    salt = bytes.fromhex(salt_hex)
    db_key = bytes.fromhex(db_key_hex)

    # 与创建时一致:密码+PEPPER拼接后计算哈希
    password_input = password.encode('utf-8') + PEPPER.encode('utf-8')
    password_hash = hashlib.pbkdf2_hmac(hash_algo, password_input, salt, iterations)
 
    # 对比哈希值
    if password_hash == db_key:
        print("Login successful")
    else:
        print("Invalid password")
    
    conn.close()

关键说明

  • 十六进制字符串转换:将二进制的salt和哈希值转为十六进制字符串存储,避免pyodbc对二进制字段的自动转码问题,读取时再转回bytes即可正常用于哈希计算。
  • PEPPER一致性:登录与创建用户的哈希计算逻辑必须完全一致,否则即使密码正确,哈希值也会不匹配。
  • 字段索引确认:需根据数据库表的实际字段顺序调整account的索引值,确保取到正确的salt、哈希值等数据。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.17 15:54:56