Flask中没有哈希密码

时间:2015-05-21 19:48:06

标签: python mongodb hash flask bcrypt

我不知道为什么密码不使用Bcrypt散列。我想我做对了。我正确地启动了Bcrypt,我使用的是mongoengine。每当我查看数据库时,它仍然会在文本中显示未加密的密码。

用户/ 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)

用户/ 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)

用户/ 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

这是我搜索mongodb shell时的结果。密码没有哈希。

{ "_id" : ObjectId("555df97deddd5543c360888a"), "username" : "FullMetal", "first_name" : "Edward", "last_name" : "Elric", "email" : "fullmetalalchemist@gmail.com", "password" : "equalexchange" }

3 个答案:

答案 0 :(得分:4)

该属性名为hash_password而不是password。我没有看到hash_password被分配的位置(即调用其setter时)。此外,您的setter方法应该与属性本身具有完全相同的名称,在这种情况下hash_password not(set_hash_password)。然后你可以做

user = User(hash_password=form.password.data)

不幸的是,由于mongoengine.Document.__init__的工作方式,您将无法以这种方式使用您的字段。您有两种方法可以使其工作:

选项1:首先创建没有密码的User对象,然后设置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:需要覆盖__init__

User方法
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(first_name=form.first_name.data, hash_password=form.password.data)

答案 1 :(得分:2)

Python @property装饰器不适用于old-style类。我做了这个演示 - 注意继承自object的类,这使它成为一个新风格的类。看看并修改它以满足您的需要

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))

只需移除@property类中的User setter和getter。

答案 2 :(得分:0)

以下是我在同样情况下所做的事情:

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()

这样你的逻辑就会停留在你的模型中,但可以从外面轻松调用。