Ali*_*aki 8 python bcrypt flask
我正在使用Flask和flask-Bcrypt完成一个简单的用户登录.但是,当尝试使用存储在我的数据库中的用户登录时,我不断收到此错误
ValueError: Invalid salt
Run Code Online (Sandbox Code Playgroud)
models.py
class User(db.Model):
__tablename__ = "users"
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String, nullable=False)
email = db.Column(db.String, nullable=False)
password = db.Column(db.String, nullable=False)
posts = db.relationship("Post", backref="author", lazy="dynamic")
def __init__(self, name, email, password):
self.name = name
self.email = email
self.password = bcrypt.generate_password_hash(password)
def __repr__(self):
return '<User {}>'.format(self.name)
Run Code Online (Sandbox Code Playgroud)
views.py
@app.route("/login", methods=["GET", "POST"])
def login():
form = LoginForm()
if form.validate_on_submit():
user = User.query.filter(User.name == form.username.data).first()
if user and bcrypt.check_password_hash(user.password, form.password.data):
flash("you were just logged in!")
login_user(user)
return redirect(url_for("home"))
else:
flash("bad username or password")
return render_template("login.html", form=form)
Run Code Online (Sandbox Code Playgroud)
forms.py
class LoginForm(Form):
username = StringField('username', validators=[DataRequired()])
password = PasswordField('password', validators=[DataRequired()])
Run Code Online (Sandbox Code Playgroud)
小智 12
我的问题类似于@tomClark所描述的
我用的Postgres作为我DDBB和他的司机,或DDBB系统,编码总是一个已编码的字符串.第二个编码过程创建一个无效的哈希,如下所示:
'\\x24326224313224483352757749766438764134333757365142464f4f4f464959664d66673575??467873754e466250716f3166375753696955556b2e36'
Run Code Online (Sandbox Code Playgroud)
正确的哈希看起来像这样:
$2b$12$Wh/sgyuhro5ofqy2.5znc.35AjHwTTZzabz.uUOya8ChDpdwvROnm
Run Code Online (Sandbox Code Playgroud)
要解决它,我首先将哈希解码为utf8,而不是将其保存到DDBB.
示例代码:
def set_password(self, pw):
pwhash = bcrypt.hashpw(pw.encode('utf8'), bcrypt.gensalt())
self.password_hash = pwhash.decode('utf8') # decode the hash to prevent is encoded twice
Run Code Online (Sandbox Code Playgroud)
Bob*_*dan 10
您需要申请.decode('utf-8')您的self.password:
def set_password(self, password):
"""Set password."""
self.password = bcrypt.generate_password_hash(password).decode('utf-8')
Run Code Online (Sandbox Code Playgroud)
如果在散列密码时出现任何问题,似乎也会返回此异常.
从bcrypt来源hashpw():
hashed = _bcrypt.ffi.new("unsigned char[]", 128)
retval = _bcrypt.lib.crypt_rn(password, salt, hashed, len(hashed))
if not retval:
raise ValueError("Invalid salt")
Run Code Online (Sandbox Code Playgroud)
该bcrypt(其中包Flask-Bcrypt用来完成工作)返回ValueError: Invalid salt时调用操作系统的bcrypt lib中返回一个错误.因此,如果由于某种原因它根本无法调用bcrypt lib,它仍将(错误地)返回Invalid salt错误.
似乎是bcrypt包实现中的一个缺陷- 它应该检查特定的值retval.
在我的情况下,错误结果与Apache mod_wsgi中的运行Flask有关virtualenv.我可以直接运行flask没有问题(使用flask-cli),但完全相同的应用程序实例bcrypt在运行时不会成功使用mod_wsgi.
通过修改我的Apache配置以使用virtualenv作为主要的Python环境来解决这个问题mod_wsgi.
在httpd.conf或/etc/httpd/conf.d/...添加:
WSGIPythonHome /path/to/my/application-virtualenv
Run Code Online (Sandbox Code Playgroud)
有关此配置的更多信息,请参见此处:虚拟环境 - mod_wsgi文档
我仍然怀疑我的特定问题与我的系统的python站点包或其他与python包含相关的东西有关.
编辑:设置WSGIPythonHome结果不是解决问题.最后我用nginx切换到uWSGI.
就我而言,问题与密码存储期间进行的类型转换有关.使用bcrypt.generate_password_hash(plaintext)返回二进制值,如b'$2b$12$zf/TxXZ4JJZ/lFX/BWALaeo0M.wNXrQXLqIFjmZ0WebqfVo9NES56'.
与我的一样,您的密码列设置为字符串:
password = db.Column(db.String, nullable=False)
Run Code Online (Sandbox Code Playgroud)
我发现上面生成哈希值,将二进制值存储在我的字符串密码列中,然后只是检索它导致了由于SQLAlchemy的类型转换而产生的不同值 - 与bcrypt完全无关!
关于正确列类型的问题帮助我意识到,为了正确的往返,我必须将密码存储为二进制.尝试使用以下代码替换列定义:
password = db.Column(db.Binary(60), nullable=False)
Run Code Online (Sandbox Code Playgroud)
我不确定,但建议不同的生产环境和数据库可以不同地处理这种类型的转换(在某些情况下可逆转,而不是在其他情况下),或许可以解释@Samuel Jaeschke所带来的混合成功.
这也解释了为什么将输入字符串编码为约束字符集(较早的解决方案)在某些情况下可能有所帮助而不是其他情况 - 如果它导致从/到类型转换工作,那么您将从数据库中恢复正确的散列比较.
无论如何,这为我解决了这个问题.
小智 6
基本上你想在散列之前对你的数据进行编码:password.encode('utf-8')。如果它以 unicode 形式出现,则可能会引发错误。也看看这里:https : //github.com/maxcountryman/flask-bcrypt/issues/9
小智 5
我相信您正在使用 python 3 和 bcrypt0.7.1。首先,您必须删除数据库中的用户,然后转到您的模型并将 .decode('utf-8') 添加到 generate_password_hash() 方法中,如下所示:
pw_hash = bcrypt.generate_password_hash(‘hunter2’).decode('utf-8')
Run Code Online (Sandbox Code Playgroud)
或者,您可以卸载flask-bcrypt==0.7.1 并安装flask-bcrypt==0.62。确保在安装 flask-bcrypt==0.62 之前从表中删除用户
小智 5
我有一个类似的问题。我检查密码的代码如下:
if check_password_hash(form.password.data, user.pw_hashed):
Run Code Online (Sandbox Code Playgroud)
当我颠倒顺序时:
if check_password_hash(user.pw_hashed, form.password.data):
Run Code Online (Sandbox Code Playgroud)
它运作良好。