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

Flask项目中user_db.hashed_password查询返回None的原因排查

问题描述

在Flask项目中,查询数据库得到user_db变量后,调用flash(user_db.username)和flash(user_db.email)可正常输出对应值,但调用flash(user_db.hashed_password)时返回None。相关代码如下:

from flask import Flask
app = Flask(__name__)


class User(UserMixin, db.Model):
    id = db.Column(db.Integer, primary_key=True)
    username = db.Column(db.String(80), unique=True)
    hashed_password = db.Column(db.String(128))
    email = db.Column(db.String(120), unique=True)
    
 
    from argon2 import PasswordHasher

    def hash_password(self, plaintext_password_form):
        ph = PasswordHasher()
        self.password_hashed_form  = ph.hash(plaintext_password_form)
        return self.password_hashed_form 
    


    
    def compare_hashed_passwords(self, hashed_password_db, plaintext_password_form):
        '''   
        The code runs in the /login route.
        You should query the db for hashed_password 
        or the value will be a different hash; 
        and the function ph.verify will return False even 
        if the password form match with the hash password.
        '''
        
        ph = PasswordHasher()
        try:
            ph.verify(hashed_password_db, plaintext_password_form)
            signedin = True
        except:
            signedin = False
        return signedin
        # have to redirect 
    


@app.route("/home", methods = ['POST', 'GET'])
def home():
   render_template(home.html)





class RegistrationForm(FlaskForm):
    '''
    This is in /register route.
    The forms are username, email, password and confirm_password
    '''
    username = StringField('username')
    
    email = StringField('email')


    password = PasswordField('password')
 
    confirm_password = PasswordField('confirm_password')
    submit = SubmitField('Submit'),



   

@app.route("/register", methods = ['POST', 'GET'])
def register():

    # if the user is logged in make so they can't go to the register page. 
    if current_user.is_authenticated:
        return redirect(url_for(('auth.home')))
    
    form = RegistrationForm()
    # form.validate_on_submit(): are always the same line of render template to always allow a get request.
    if form.validate_on_submit():

        username_form = form.username.data
        email_form = form.email.data
        plaintext_password_form = form.password.data
        confirm_plaintext_password_form = form.confirm_password.data
        # Use the code, if you are adding code to the database the first time
        adding_user = User(username=username_form, email=email_form)
        # hash the password    
        hashed_password_form = adding_user.hash_password(plaintext_password_form)
        
     
        
        adding_user_hahed_password = User(hashed_password=hashed_password_form)
        db.session.add(adding_user, adding_user_hahed_password )
        db.session.commit()
               
       
        return redirect(url_for('auth.login'))
    return render_template('register.html',title='register', form=form)





def check_if_username_or_email_is_in_db(form, field):
    '''
    if the username or email is in the db the code works,
    if not it raises an ValidationError.
    The if statement checks if the query is empty/has no values in db.
    This runs in the LoginForm in auth/forms.py
    '''
  
 
    # if empty list [] return True 
    if not User.query.filter_by(username=field.data).first() or not User.query.filter_by(username=field.data).first(): 
        raise ValidationError('The username or email does not exist. Please retype your username or email.')   



# I included this validator because I am not sure if that could be causing the error. 
class LoginForm(FlaskForm):
    '''
    This is in /Login route.
    The forms are username, email, password and confirm_password
    '''
    
    username_or_email = StringField('username_or_email', validators=
    [
    check_if_username_or_email_is_in_db
    ])    
    
    password = PasswordField('password')
    submit = SubmitField('Submit')
  



@app.route("/login",methods = ['POST', 'GET'])
def login():
    # if the user is logged in make it so they can't go to the login page. 
    if current_user.is_authenticated:
        return redirect(url_for('auth.home')) 

    form = LoginForm()
    if form.validate_on_submit():

        # allows you to register with a username or email
        username_or_email_form = form.username_or_email.data
        plaintext_password_form = form.password.data
 

        username_db = User.query.filter_by(username=username_or_email_form).first()
        email_db = User.query.filter_by(email=username_or_email_form).first()
                
        if username_db.username == username_or_email_form:
            user_db = User.query.filter_by(username=username_or_email_form ).first()
            flash(user_db)

        elif email_db.email == username_or_email_form:
            user_db = User.query.filter_by(email=username_or_email_form).first()
        else:
            flash('username or email do not exist')
            flash(user_db)
        
               
        flash(user_db.hashed_password)
        
        hashed_password_db = user_db.hashed_password
        return render_template('home.html')

           

if __name__ == '__main__':
app.run(debug=True)
问题原因及解决办法

导致hashed_password返回None的核心原因是注册逻辑错误,密码哈希值根本没存入正确的用户记录中,同时User类的密码哈希方法也存在字段不匹配问题,具体问题及修复如下:

1. 注册时创建了两个独立的User对象(最核心问题)

在register路由中,你先创建了包含用户名和邮箱的adding_user,又创建了仅包含哈希密码的adding_user_hahed_password,还将两个对象都添加到数据库。这会生成两条独立的用户记录:一条只有用户名和邮箱,另一条只有哈希密码,所以登录时查到的用户记录自然没有hashed_password值。

修复方式:只创建一个User对象,一次性设置所有字段。

2. User类的hash_password方法赋值字段错误

hash_password方法中给self.password_hashed_form赋值,但数据库字段名是hashed_password,导致哈希密码没赋值到正确的对象属性上,即使逻辑正确也存不进数据库。

修复方式:修改方法内的赋值为self.hashed_password。

3. 其他次要问题(避免后续报错)

  • home路由缺少return语句,会触发500错误;
  • check_if_username_or_email_is_in_db验证器的判断重复,应同时检查用户名和邮箱;
  • login路由中如果username_db为None,直接访问username_db.username会抛出AttributeError,需先判断对象是否存在。

修正后的核心代码示例

修正后的User类

class User(UserMixin, db.Model):
    id = db.Column(db.Integer, primary_key=True)
    username = db.Column(db.String(80), unique=True)
    hashed_password = db.Column(db.String(128))
    email = db.Column(db.String(120), unique=True)
    
    from argon2 import PasswordHasher

    def hash_password(self, plaintext_password_form):
        ph = PasswordHasher()
        # 赋值给数据库对应的字段名hashed_password
        self.hashed_password = ph.hash(plaintext_password_form)
        return self.hashed_password 

修正后的register路由

@app.route("/register", methods = ['POST', 'GET'])
def register():
    if current_user.is_authenticated:
        return redirect(url_for('home'))
    
    form = RegistrationForm()
    if form.validate_on_submit():
        username_form = form.username.data
        email_form = form.email.data
        plaintext_password_form = form.password.data
        
        # 只创建一个User对象
        adding_user = User(username=username_form, email=email_form)
        # 直接调用方法给对象的hashed_password赋值
        adding_user.hash_password(plaintext_password_form)
        
        # 只添加这一个对象到数据库
        db.session.add(adding_user)
        db.session.commit()
               
        return redirect(url_for('login'))
    return render_template('register.html',title='register', form=form)

修正后的login路由(避免None报错)

@app.route("/login",methods = ['POST', 'GET'])
def login():
    if current_user.is_authenticated:
        return redirect(url_for('home')) 

    form = LoginForm()
    if form.validate_on_submit():
        username_or_email_form = form.username_or_email.data
        plaintext_password_form = form.password.data

        # 一次性查询是否存在用户名或邮箱匹配的用户
        user_db = User.query.filter(
            (User.username == username_or_email_form) | 
            (User.email == username_or_email_form)
        ).first()
        
        if user_db:
            flash(user_db.username)
            flash(user_db.email)
            flash(user_db.hashed_password)  # 现在会正常输出哈希密码
            # 此处可继续添加密码验证逻辑
        else:
            flash('用户名或邮箱不存在')
        
        return render_template('home.html')

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.08 15:37:32