不在 Flask 中散列密码
Not hashing password in Flask
我不知道为什么密码没有使用 Bcrypt 进行哈希处理。我认为我做对了。我正确地初始化了 Bcrypt,并且我正在使用 mongoengine。每次我查看数据库时,它仍然以文本形式显示未加密的密码。
users/models.py
from app import db, bcrypt
class User(db.Document):
username = db.StringField(required=True)
first_name = db.StringField(required=True)
last_name = db.StringField(required=True)
email = db.EmailField(required=True)
password = db.StringField(required=True)
meta = {'collection': 'users'}
@property
def hash_password(self):
return self.password
@hash_password.setter
def set_hash_password(self, password):
self.password = bcrypt.generate_password_hash(password)
def verify_password(self, password):
return bcrypt.check_password_hash(self.password, password)
users/views.py
@userV.route('/signup', methods=['GET', 'POST'])
def signup():
form = SignUpForm()
if form.validate_on_submit():
user = User(
first_name=form.first_name.data,
last_name=form.last_name.data,
username=form.username.data,
email=form.email.data,
password=form.password.data
).save()
flash('You can now login')
return render_template('user.html', variable="You can now login " + user.username)
return render_template('signup.html', form=form)
users/auth/forms.py
class SignUpForm(Form):
username = StringField('Username', validators=[
InputRequired(message="Username is required"),
Regexp('^[A-Za-z][A-Za-z0-9_]*[A-Za-z0-9]$', 0, 'Usernames must have only letters, numbers or underscores')
])
first_name = StringField('First Name', validators=[
InputRequired(message="First name is required")
])
last_name = StringField('Last Name', validators=[
InputRequired(message="Last name is required")
])
email = StringField('Email Address', validators=[
InputRequired(message="Email is required"),
Email(message="This is not a valid email")
])
password = PasswordField('Password', validators=[
InputRequired(message="Password is required"),
Length(min=6, message="The password is not long enough")
])
accept_tos = BooleanField('Accept Terms of Service', validators=[
InputRequired(message="You have to accept the Terms of Service in order to use this site")
])
submit = SubmitField('Signup')
def validate(self):
if not Form.validate(self):
return False
if User.objects(username=self.username.data).first():
raise ValidationError('Username already in use')
if User.objects(email=self.email.data).first():
raise ValidationError('Email already registered')
return True
这是我搜索mongodbshell时的结果。密码未经过哈希处理。
{ "_id" : ObjectId("555df97deddd5543c360888a"), "username" : "FullMetal", "first_name" : "Edward", "last_name" : "Elric", "email" : "fullmetalalchemist@gmail.com", "password" : "equalexchange" }
Python @property
装饰器不适用于 old-style classes。我制作了这个演示 - 注意 class 继承自 object
,这使它成为一种新样式 class。查看并修改它以满足您的需要
class User(object):
def __init__(self, username, first_name, last_name, email, password):
print "Initializing"
self.username = username
self.first_name = first_name
self.last_name = last_name
self.email = email
self.password = password
@property
def password(self):
print "getting password"
return self._password
@password.setter
def password(self, password):
print "Setting password"
self._password = bcrypt.generate_password_hash(password)
def verify_password(self, password):
return bcrypt.check_password_hash(self.password, password)
正如我之前提到的,如果一切都失败了,我将通过执行我认为的逻辑来解决这个问题。这就是我首先要做的,tbh。 Python 喜欢表现力。
其他部分我省略了
user = User(password=bcrypt.generate_password_hash(form.password.data))
并且只需删除 User
class 中的 @property
setter 和 getter。
属性 称为 hash_password
而不是 password
。我没有看到 hash_password
在哪里被分配(那是它的 setter 被调用的时候)。此外,您的 setter 方法应与 属性 本身具有完全相同的名称,在本例中为 hash_password
而不是 (set_hash_password
)。然后你可以做
user = User(hash_password=form.password.data)
很遗憾,由于 mongoengine.Document.__init__
的工作方式,您将无法以这种方式使用您的字段。您有两个选项可以让它发挥作用:
方案一:先创建没有密码的用户对象,然后设置hash_password,然后保存
user = User(first_name=form.first_name.data,
last_name=form.last_name.data,
username=form.username.data,
email=form.email.data)
user.hash_password = form.password.data
user.save()
选项 2:需要覆盖 User
的 __init__
方法
class User(db.Document):
def __init__(self, *args, **kwargs):
if 'hash_password' in kwargs:
self.hash_password = kwargs.pop('hash_password')
super(User, self).__init__(*args, **kwargs)
现在您可以按照最初的需要使用 User 了:
user = User(first_name=form.first_name.data, hash_password=form.password.data)
以下是我在相同情况下的做法:
class User(db.Document):
...
password = db.StringField(max_length=255, required=True)
...
def set_password(self, password):
self.password = bcrypt.generate_password_hash(password)
...
然后,在 views.py 中,我执行以下操作:
user = User(..)
user.set_password(form.password.data)
user.save()
这样您的逻辑就保留在您的模型中,但可以很容易地从外部调用。
我不知道为什么密码没有使用 Bcrypt 进行哈希处理。我认为我做对了。我正确地初始化了 Bcrypt,并且我正在使用 mongoengine。每次我查看数据库时,它仍然以文本形式显示未加密的密码。
users/models.py
from app import db, bcrypt
class User(db.Document):
username = db.StringField(required=True)
first_name = db.StringField(required=True)
last_name = db.StringField(required=True)
email = db.EmailField(required=True)
password = db.StringField(required=True)
meta = {'collection': 'users'}
@property
def hash_password(self):
return self.password
@hash_password.setter
def set_hash_password(self, password):
self.password = bcrypt.generate_password_hash(password)
def verify_password(self, password):
return bcrypt.check_password_hash(self.password, password)
users/views.py
@userV.route('/signup', methods=['GET', 'POST'])
def signup():
form = SignUpForm()
if form.validate_on_submit():
user = User(
first_name=form.first_name.data,
last_name=form.last_name.data,
username=form.username.data,
email=form.email.data,
password=form.password.data
).save()
flash('You can now login')
return render_template('user.html', variable="You can now login " + user.username)
return render_template('signup.html', form=form)
users/auth/forms.py
class SignUpForm(Form):
username = StringField('Username', validators=[
InputRequired(message="Username is required"),
Regexp('^[A-Za-z][A-Za-z0-9_]*[A-Za-z0-9]$', 0, 'Usernames must have only letters, numbers or underscores')
])
first_name = StringField('First Name', validators=[
InputRequired(message="First name is required")
])
last_name = StringField('Last Name', validators=[
InputRequired(message="Last name is required")
])
email = StringField('Email Address', validators=[
InputRequired(message="Email is required"),
Email(message="This is not a valid email")
])
password = PasswordField('Password', validators=[
InputRequired(message="Password is required"),
Length(min=6, message="The password is not long enough")
])
accept_tos = BooleanField('Accept Terms of Service', validators=[
InputRequired(message="You have to accept the Terms of Service in order to use this site")
])
submit = SubmitField('Signup')
def validate(self):
if not Form.validate(self):
return False
if User.objects(username=self.username.data).first():
raise ValidationError('Username already in use')
if User.objects(email=self.email.data).first():
raise ValidationError('Email already registered')
return True
这是我搜索mongodbshell时的结果。密码未经过哈希处理。
{ "_id" : ObjectId("555df97deddd5543c360888a"), "username" : "FullMetal", "first_name" : "Edward", "last_name" : "Elric", "email" : "fullmetalalchemist@gmail.com", "password" : "equalexchange" }
Python @property
装饰器不适用于 old-style classes。我制作了这个演示 - 注意 class 继承自 object
,这使它成为一种新样式 class。查看并修改它以满足您的需要
class User(object):
def __init__(self, username, first_name, last_name, email, password):
print "Initializing"
self.username = username
self.first_name = first_name
self.last_name = last_name
self.email = email
self.password = password
@property
def password(self):
print "getting password"
return self._password
@password.setter
def password(self, password):
print "Setting password"
self._password = bcrypt.generate_password_hash(password)
def verify_password(self, password):
return bcrypt.check_password_hash(self.password, password)
正如我之前提到的,如果一切都失败了,我将通过执行我认为的逻辑来解决这个问题。这就是我首先要做的,tbh。 Python 喜欢表现力。 其他部分我省略了
user = User(password=bcrypt.generate_password_hash(form.password.data))
并且只需删除 User
class 中的 @property
setter 和 getter。
属性 称为 hash_password
而不是 password
。我没有看到 hash_password
在哪里被分配(那是它的 setter 被调用的时候)。此外,您的 setter 方法应与 属性 本身具有完全相同的名称,在本例中为 hash_password
而不是 (set_hash_password
)。然后你可以做
user = User(hash_password=form.password.data)
很遗憾,由于 mongoengine.Document.__init__
的工作方式,您将无法以这种方式使用您的字段。您有两个选项可以让它发挥作用:
方案一:先创建没有密码的用户对象,然后设置hash_password,然后保存
user = User(first_name=form.first_name.data,
last_name=form.last_name.data,
username=form.username.data,
email=form.email.data)
user.hash_password = form.password.data
user.save()
选项 2:需要覆盖 User
__init__
方法
class User(db.Document):
def __init__(self, *args, **kwargs):
if 'hash_password' in kwargs:
self.hash_password = kwargs.pop('hash_password')
super(User, self).__init__(*args, **kwargs)
现在您可以按照最初的需要使用 User 了:
user = User(first_name=form.first_name.data, hash_password=form.password.data)
以下是我在相同情况下的做法:
class User(db.Document):
...
password = db.StringField(max_length=255, required=True)
...
def set_password(self, password):
self.password = bcrypt.generate_password_hash(password)
...
然后,在 views.py 中,我执行以下操作:
user = User(..)
user.set_password(form.password.data)
user.save()
这样您的逻辑就保留在您的模型中,但可以很容易地从外部调用。