Python验证加密密码时触发TypeError:需bytes类对象而非str
解决登录验证时的TypeError及密码哈希不匹配问题
问题根源
- 二进制数据存储/读取格式不兼容:Access数据库存储二进制数据(salt、哈希值)后,通过pyodbc读取时会自动转为十六进制字符串,而
hashlib.pbkdf2_hmac要求传入bytes类型参数,因此触发TypeError: a bytes-like object is required, not 'str'。 - 哈希计算逻辑不一致:创建用户时计算哈希会将密码与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
相关产品推荐
相关产品推荐

