bcrypt.checkpw返回 TypeError: Unicode-objects must be encoded before checking。

33

我正在调用 bcrypt.checkpw 函数来检查未加密密码是否与凭据数据库中存储的哈希密码匹配,但是却收到以下报错:

TypeError: Unicode-objects must be encoded before checking

我应该如何解决这个问题?有什么建议吗?
我已安装 python 2.7.6bcrypt 3.1.1

我有以下代码:

def check_password(password, hashed_password)
    if not bcrypt.checkpw(password, hashed_password):
        raise InvalidCredentials("403 Forbidden")
    else:
        return true

并且收到以下错误:

文件 "/home/qt/virtualenv/lib/python2.7/site-packages/bcrypt/init.py",第100行,checkpw函数中, 抛出 TypeError("Unicode-objects must be encoded before checking")
TypeError: Unicode-objects must be encoded before checking

我查看了 bcrypt/__init__.py,但不确定原因。

def checkpw(password, hashed_password):    
    if (isinstance(password, six.text_type) or            
        isinstance(hashed_password, six.text_type)):        
    raise TypeError("Unicode-objects must be encoded before checking")
4个回答

36

我假设你使用的是Python 3。在Python 3中,默认情况下,字符串是Unicode字符串。

如果你用Unicode值调用bcrypt.checkpw()函数:

import bcrypt

password = "seCr3t"  # unicode string
hashed_password = "hashed_seCr3t"  # unicode string

bcrypt.checkpw(password, hashed_password)

你会得到这个异常

Traceback (most recent call last):
  ...
TypeError: Unicode-objects must be encoded before checking

原因很简单:加密函数只对字节字符串(或数组)有效。

您的passwordhashed_password必须都是字节字符串。

如果使用bcrypt.hashpw()函数,则hashed_password必须是字节字符串,我认为问题在于password值。这个password必须来自HTML表单或类似的内容。要使用bcrypt.checkpw()函数,必须先使用与bcrypt.hashpw()函数加密password时相同的编码对字符串值进行编码。通常我们选择“utf8”编码。

例如(Python 2&3):

import bcrypt

# at creation first:
password = u"seCr3t"
hashed_password = bcrypt.hashpw(password.encode('utf8'), bcrypt.gensalt())

# first attempt:
password = u"seCrEt"
bcrypt.checkpw(password.encode('utf8'), hashed_password)
# -> False

# second attempt:
password = u"seCr3t"
bcrypt.checkpw(password.encode('utf8'), hashed_password)
# -> True

请查看Github页面中的简单用法


感谢Laurent的快速回复和清晰的代码示例!我正在使用Python 2.7.6。我尝试了你的建议,它可以正常运行。我认为在Python 2.7.6中,默认情况下字符串是Unicode字符串。 - user7153744
2
不,Python 2默认使用字节字符串。如果您想要Unicode字符串,需要使用“u”前缀,例如:u"foo",或者使用decode()方法将字节字符串转换为Unicode字符串。Unicode字符串应该来自于HTML表单或类似的输入:这是经典(也是预期的)行为。 - Laurent LAPORTE
嗯..所以用Python 2,我的原始代码应该可以工作,因为密码和哈希密码都是字节字符串。那么为什么在这种情况下我会得到异常呢?password = "seCr3t" # 字节字符串 hashed_password = "hashed_seCr3t" # 字节字符串 bcrypt.checkpw(password, hashed_password) - user7153744
我在Python 2.7.10上尝试了它。在我的本地环境下工作正常,但是当我部署到Heroku时,它一直抛出错误。 - Elesin Olalekan Fuad
你需要更多的解释吗?如果不需要,我建议你给我的回答点赞并接受 - Laurent LAPORTE
显示剩余2条评论

14

你可以像这样做一些事情

bcrypt.checkpw(password.encode('utf-8'), hashed_password)

简单就是美


现在会抛出错误 AttributeError: 'bytes' object has no attribute 'encode' - Hercislife
这应该有效:bcrypt.checkpw(password.encode('utf-8'), hashed_password)。我会更新答案。 - Sunday Ikpe

9
我使用类似这样的东西。
class User(Base):
    __tablename__ = "user"
    id = Column(BigInteger, primary_key=True, autoincrement=True)

    login = Column(String, nullable=False, unique=True)
    password = Column(String, nullable=False)

    @staticmethod
    def make_password_hash(password):
        hash = bcrypt.hashpw(password=password.encode('utf-8'), salt=bcrypt.gensalt())
        return hash.decode('utf-8')

    def is_password_valid(self, password):
        return bcrypt.checkpw(password.encode('utf-8'), self.password.encode('utf-8'))

1
这对我有用。在存储到数据库之前,我必须解码哈希密码,并在使用新密码进行检查之前再次编码它...谢谢! - FATCHOLA
这救了我的一天!我们为什么要在存储到数据库之前进行解码呢? - MisterCat

0

使用例如这样的方式,并查看代码下面的注释:

import bcrypt

def comparacaoSenha(passw, hash):
    if bcrypt.checkpw(passw, hash):
        print("It Matches!")
    else:
            print("It Does not Match")

password = "super secret password".encode('utf-8')
password2 = "another password".encode('utf-8')

hashed = bcrypt.hashpw(password, bcrypt.gensalt())
heashed2 = bcrypt.hashpw(password2, bcrypt.gensalt())

print("Teste 1: ")
print("-----------------------------")
print("PASSWORD: ", password)
print("HASHED PW: ", hashed)
comparacaoSenha(password, hashed)
print("-----------------------------")

print("Teste 2: ")
print("-----------------------------")
print("PASSWORD: ", password2)
print("HASHED PW: ", heashed2)
comparacaoSenha(password2, heashed2)
print("-----------------------------")

# Things to remember:
# always use the encode('utf-8') or put a prefix 'b'' just before the strings
# EX: newPass = b"OTHER PASSWORD" // or newPass="OTHER PASSWORD".encode('utf-8')
# 

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接