Flask+SQLite登录验证报错:coercing to Unicode: sqlite3.Cursor found
问题根源:把游标对象当成查询结果使用
嘿,这个错误TypeError: coercing to Unicode: need string or buffer, sqlite3.Cursor found的原因一眼就能看出来——你直接把cur.execute()返回的游标对象赋值给了pwd、uname和salt变量,而不是从游标里提取实际的查询数据!游标本身只是一个指向结果集的"指针",不是你要的字符串或数值,当hash_password函数尝试把游标和密码拼接时,自然会触发Unicode转换错误。
另外,你的代码还有个严重的安全隐患:用字符串拼接SQL语句会招来SQL注入攻击,必须立刻改成参数化查询。
修正后的登录路由代码
我帮你重写了核心逻辑,同时修复了上述两个问题,还简化了冗余的查询操作:
@app.route('/login', methods=['POST', 'GET']) def do_admin_login(): if request.method == "POST": username = request.form['username'] password = request.form['password'] # 使用参数化查询彻底避免SQL注入 with sql.connect("database.db") as con: cur = con.cursor() # 一次查询获取用户的密码哈希和盐值,减少数据库交互 cur.execute("SELECT pword, salt FROM logins WHERE uname = ?", (username,)) user_data = cur.fetchone() if not user_data: # 用户不存在,统一提示避免泄露信息 flash('Wrong username or password!') return render_template('login.html') stored_pwd, salt = user_data # 验证密码 hashed_password = hash_password(password, salt) if hashed_password == stored_pwd: session['logged_in'] = True flash('Right password!') return render_template('home.html') else: flash('Wrong username or password!') return render_template('login.html') else: return render_template('login.html')
关键修复点说明
- 获取真实查询结果:用
cur.fetchone()获取单条记录,它会返回一个元组(比如(存储的密码哈希, 盐值)),直接解构赋值就能拿到你需要的具体数据;如果用户不存在,fetchone()会返回None,我们可以直接判断并提示错误。 - 参数化查询:把SQL里的变量用
?占位,参数放在元组里传给execute(),既避免了SQL注入,也不用手动处理字符串转义的麻烦。 - 简化逻辑:原来的三个查询合并成一个,减少数据库交互次数,提升性能。
- 移除冗余操作:
con.commit()和con.close()都不需要——with语句会自动管理连接的关闭,查询操作也不需要提交事务。
额外优化建议
- 给
hash_password函数加个防御性判断,避免salt为空的情况:
def hash_password(password, salt): if not salt: raise ValueError("Salt cannot be empty") password_string = (password + salt).encode('utf-8') hashed_password = hashlib.sha512(password_string).hexdigest() return hashed_password
- 错误提示统一用"用户名或密码错误",不要区分两种情况,避免泄露用户存在性的敏感信息,提升账号安全性。
内容的提问来源于stack exchange,提问作者Buhlahkay
相关产品推荐
相关产品推荐

