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

Flask简易登录页面哈希密码验证失败问题排查

问题分析与解决方案

你的问题出在Flask-Scrypt的API使用错误以及bytes与字符串的类型处理不一致,导致验证时哈希对比失败。以下是具体问题和修正方案:

问题1:密码哈希生成时的错误拼接

在set_password方法中,你错误地将密码bytes与salt直接拼接后传入generate_password_hash,但Flask-Scrypt的generate_password_hash会自动处理密码与salt的结合,不需要手动拼接。同时,生成的哈希是bytes类型,直接存入数据库会导致存储的是bytes的字符串表示(如b'xxx'),但实际验证时需要原始bytes。

问题2:验证时的参数与类型错误

check_password_hash的正确参数是:check_password_hash(stored_hash, password, salt),其中stored_hash和salt都需要是bytes类型。但你存储的是字符串类型的哈希和salt,验证时直接传入字符串,导致类型不匹配。


修正后的代码

models.py

# app/models.py

from . import db
from flask_scrypt import generate_random_salt, generate_password_hash, check_password_hash
import base64

class User(db.Model):
    __tablename__ = 'users'
    userID = db.Column('userID', db.Integer, primary_key=True)
    username = db.Column('username', db.String(50), unique=True, nullable=False)
    password_hash = db.Column('password_hash', db.String(200), nullable=False)
    salt = db.Column('salt', db.String(200), nullable=False)

    def __init__(self, username, password):
        self.username = username
        self.set_password(password)

    def set_password(self, password):
        # 生成bytes类型的salt
        salt_bytes = generate_random_salt()
        # 将salt转成base64字符串存储,避免编码问题
        self.salt = base64.b64encode(salt_bytes).decode('utf-8')
        print("Salt before hashing:", self.salt)  # Debugging
        
        password_bytes = password.encode('utf-8')
        # 直接传入密码bytes和salt bytes,无需手动拼接
        hash_bytes = generate_password_hash(password_bytes, salt=salt_bytes)
        # 将哈希转成base64字符串存储
        self.password_hash = base64.b64encode(hash_bytes).decode('utf-8')

    def check_password(self, password):
        print("Checking password for user:", self.username)
        password_bytes = password.encode('utf-8')
        
        # 将存储的salt和哈希字符串转回bytes
        salt_bytes = base64.b64decode(self.salt)
        stored_hash_bytes = base64.b64decode(self.password_hash)
        
        # 调用check_password_hash的正确方式:传入存储的哈希bytes、密码bytes、salt bytes
        is_valid = check_password_hash(stored_hash_bytes, password_bytes, salt=salt_bytes)
        
        # 调试用:重新生成哈希对比(可选)
        attempt_hash_bytes = generate_password_hash(password_bytes, salt=salt_bytes)
        attempt_hash = base64.b64encode(attempt_hash_bytes).decode('utf-8')
        print("Hashed password from attempt:", attempt_hash)
        print("Stored hashed password:", self.password_hash)
        
        return is_valid

关键修正点说明

  1. 统一bytes与字符串的转换:用base64编码将bytes转成字符串存储,避免直接存bytes导致的编码问题,验证时再解码回bytes。
  2. 正确调用Flask-Scrypt API:
    • generate_password_hash(password_bytes, salt=salt_bytes):直接传密码和salt的bytes,无需手动拼接。
    • check_password_hash(stored_hash_bytes, password_bytes, salt=salt_bytes):传入存储的哈希bytes、原始密码bytes、salt bytes。
  3. 避免类型不匹配:确保存储和验证时的哈希、salt类型一致(存储为base64字符串,验证时转回bytes)。

测试时,需要重新创建用户(因为之前存储的哈希和salt格式不正确),然后再尝试登录即可验证通过。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.26 00:38:15