Bcrypt哈希返回TypeError(“必须在哈希之前对Unicode对象进行编码”)和无效的盐

时间:2018-06-26 23:26:02

标签: python flask bcrypt salt

我已经查看了与此相关的所有StackOverflow问题,但似乎无法弄清楚。当我对密码进行哈希处理并对其进行检查时,它将使用当前代码返回TypeError“哈希之前必须对Unicode对象进行编码”:

from scripts import tabledef
from flask import session
from sqlalchemy.orm import sessionmaker
from contextlib import contextmanager
import bcrypt

(Unrelated Python code...)

def hash_password(password):
     return bcrypt.hashpw(password.encode('utf8'), bcrypt.gensalt())


def credentials_valid(username, password):
    with session_scope() as s:
        user = s.query(tabledef.User).filter(
            tabledef.User.username.in_([username])).first()
        if user:

            return bcrypt.checkpw(password.encode('utf8'), user.password)
        else:
            return False

当我尝试通过设置user.password= user.password.encode('utf8')来解决此错误时,出现“无效盐”。

此代码有什么问题?

更新: 我通过用户的Flask输入存储密码:

import json
import sys
import os
import plotly
import pandas as pd
import numpy as np
import plotly.graph_objs as go


from scripts import tabledef
from scripts import forms
from scripts import helpers
from flask import Flask, redirect, url_for, render_template, request, session, flash, Markup
from flask_socketio import SocketIO, emit

@app.route('/', methods=['GET', 'POST'])
def login():
    if not session.get('logged_in'):
        form = forms.LoginForm(request.form)
        if request.method == 'POST':
            username = request.form['username'].lower()
            password = request.form['password']
            if form.validate():
                if helpers.credentials_valid(username, password):
                    session['logged_in'] = True
                    session['username'] = username
                    session['email'] = request.form['email']
                    session['password'] = request.form['password']
                    return json.dumps({'status': 'Login successful'})
                return json.dumps({'status': 'Invalid user/pass'})
            return json.dumps({'status': 'Both fields required'})
        return render_template('login.html', form=form)
    user = helpers.get_user()
    return render_template('home.html', user=user)

@app.route('/signup', methods=['GET', 'POST'])
def signup():
    if not session.get('logged_in'):
        form = forms.LoginForm(request.form)
        if request.method == 'POST':
            username = request.form['username'].lower()
            password = helpers.hash_password(request.form['password'])
            email = request.form['email']
            if form.validate():
                if not helpers.username_taken(username):
                    helpers.add_user(username, password, email)
                    session['logged_in'] = True
                    session['username'] = username
                    session['email'] = request.form['email']
                    session['password'] = request.form['password']
                    return json.dumps({'status': 'Signup successful'})
                return json.dumps({'status': 'Username taken'})
            return json.dumps({'status': 'User/Pass required'})
        return render_template('login.html', form=form)
    return redirect(url_for('login'))

这是我得到的错误:

/lib/python3.5/site-packages/flask/app.py", line 1718, in handle_user_exception
    reraise(exc_type, exc_value, tb)
  File "/home/suraj/Documents/Programming/current-projects/GW_Dining_Tracker/env/lib/python3.5/site-packages/flask/_compat.py", line 35, in reraise
    raise value
  File "/home/suraj/Documents/Programming/current-projects/GW_Dining_Tracker/env/lib/python3.5/site-packages/flask/app.py", line 1813, in full_dispatch_request
    rv = self.dispatch_request()
  File "/home/suraj/Documents/Programming/current-projects/GW_Dining_Tracker/env/lib/python3.5/site-packages/flask/app.py", line 1799, in dispatch_request
    return self.view_functions[rule.endpoint](**req.view_args)
  File "/home/suraj/Documents/Programming/current-projects/GW_Dining_Tracker/Flaskex-master/app.py", line 34, in login
    if helpers.credentials_valid(username, password):
  File "/home/suraj/Documents/Programming/current-projects/GW_Dining_Tracker/Flaskex-master/scripts/helpers.py", line 64, in credentials_valid
    return bcrypt.checkpw(password.encode('utf8'), user.password)
  File "/home/suraj/Documents/Programming/current-projects/GW_Dining_Tracker/env/lib/python3.5/site-packages/bcrypt/__init__.py", line 101, in checkpw
    raise TypeError("Unicode-objects must be encoded before checking")
TypeError: Unicode-objects must be encoded before checking

1 个答案:

答案 0 :(得分:1)

问题是您要从SQLAlchemy A=as.logical(c(0,0,1,1,1,0,1,1,0,0,0,1,1,1,1)) B=data.table::rleid(A) B=ave(B,B,FUN = seq_along) B[!A]=0 B [1] 0 0 1 2 3 0 1 2 0 0 0 1 2 3 4 列中获取值并将其传递给Stringbcrypt.checkpw用于Unicode字符串,它以String的形式提供值。但是str仅适用于字节字符串,因此需要bcrypt。这就是bytes所说的“在散列之前必须对Unicode对象进行编码”的意思。

在将TypeErrorbytes保存到{时,具体取决于您使用的数据库后端和DB-API库(对于某些后端,取决于数据库的配置方式)。 {1}}列中,它可能会保存s,在这种情况下,您可以只使用String取回相同的字节,但可能不会。例如,它也可以只保存s.decode()。在这种情况下,如果哈希为user.password.encode()str(s),则列值将为字符串bytes,因此,调用b'abcd'会得到{{1} },而不是"b'abcd'"

处理此问题的最干净方法是使用encode 1 -或者,也许更好的是b"b'abcd'" 2 -存储您的哈希,而不是b'abcd'列。任何支持Binary的DB-API都将按原样存储Binary(60),并将其返回为String,这正是您想要的。


1。 Binary是可选类型。如果您的DB-ABI不存在此类型,则可以使用与bytes相同的类型。如果没有,请浏览the list of types并尝试从bytes继承的其他类型。名称或首字母缩写没有“大”的代码可能会更有效,但其他任何一种都应该有效。

2。使用默认设置,Binary可打印的摘要将始终完全为60个字节。数据库通常可以更紧凑地存储诸如BINARY之类的固定宽度字段,并且比诸如_Binary之类的可变宽度字段更快地搜索它们。仅仅使用普通的bcrypt可能会很好,但它也可能像BINARY(60)一样工作,或者可能会浪费空间并像VARBINARY一样工作,等等。