Flask Admin - 在创建新用户时自动创建密码哈希?

时间:2018-03-13 20:37:01

标签: flask flask-admin

假设我有一个类似的用户模型:

class User(db.Model, UserMixin):
    id = db.Column(db.Integer, primary_key=True)
    first_name = db.Column(db.String(255))
    last_name = db.Column(db.String(255))
    email = db.Column(db.String(255), unique=True)
    password = db.Column(db.String(255))
    registered_on = db.Column(db.DateTime, nullable=True)
    roles = db.relationship('Role', secondary=roles_users,
                            backref=db.backref('users', lazy='dynamic'))

管理员观点:

class UserView(MyModelView):

    form_columns = (
        'roles',
        'first_name',
        'last_name',
        'email',
        'password',
        'registered_on',
    )

    form_args = dict(
                registered_on=dict(default=datetime.now())
            )

当我创建一个新用户时,如何使用像bcrypt这样的东西自动生成密码哈希?

5 个答案:

答案 0 :(得分:3)

我认为通过自动你的意思是它应该自动将手动提供的纯文本密码转换为哈希,但我不确定。我正在回答这个假设是正确的。

我们不会在Flask-Admin中公开我们的密码字段,但是我们通过将password定义为具有负责计算散列本身的setter的属性来处理密码如何以及何时被散列的基本问题把它塞进user._password

仅仅尝试在管理视图中添加password列作为一个天真的转变并不起作用,但是如果您使用sqlalchemy hybrid_property而不是property },用户视图的"password"列表中的form_columns看起来效果很好(正如您已经拥有的那样):

# models.py
from sqlalchemy.ext.hybrid import hybrid_property

class User(sql.Model):
    # ...

    _password = sql.Column(sql.Binary)
    _salt = sql.Column(sql.Binary, default=os.urandom(512))

    # ... 

    @hybrid_property
    def password(self):
        """Return the hashed user password."""
        return self._password

    @password.setter
    def password(self, new_pass):
        """Salt/Hash and save the user's new password."""
        new_password_hash = compute_new_password_hash(new_pass, self._salt)
        self._password = new_password_hash

# admin.py
class UserView(MyModelView):
    # ...

    form_columns = ("email", "password", ...)

编辑体验并未精确完善 - 您可能需要覆盖该字段以进行优化。以下是一些截图:

使用预设密码创建新用户:

Creating a new user with password

创建后的编辑视图:

User created, password hashed

更新用户密码:

Saving a new password

保存新密码后的编辑视图:

User updated with new hash

答案 1 :(得分:0)

您可以使用Flask-Admin的on_model-change并在提交数据库之前为其提供逻辑。

from flask_admin.contrib import sqla
from flask_security import utils

class UserAdmin(sqla.ModelView):

    def on_model_change(self, form, model, is_created):
        model.password = utils.encrypt_password(model.password)
        # as another example
        if is_created:
            model.registered_on = datetime.now()  

答案 2 :(得分:0)

我找到的最简单的选择是在User.password上添加SQLAlchemy attribute event并在更改后在其中哈希密码。这样,无论何时何地更改用户密码,都会自动将其散列。

from sqlalchemy import event
from werkzeug.security import generate_password_hash


@event.listens_for(User.password, 'set', retval=True)
def hash_user_password(target, value, oldvalue, initiator):
    if value != oldvalue:
        return generate_password_hash(value)
    return value

答案 3 :(得分:0)

在内部,Flask-Admin调用WTF的{​​{1}}来设置表单中的数据。 因此,我们可以利用如下所示的优势:

populate_obj

然后我们可以在class CustomPasswordField(PasswordField): # If you don't want hide the password you can use a StringField def populate_obj(self, obj, name): setattr(obj, name, hash_password(self.data)) # Password function 中使用它,如下所示:

ModelView

保存表单后,密码将被散列。

答案 4 :(得分:0)

您可以为PasswordField字段设置password小部件,并覆盖process_formdata方法来设置哈希。


from flask_security.utils import hash_password
from wtforms import PasswordField

class AdminPasswordField(PasswordField):

    def process_formdata(self, valuelist):
        if valuelist and valuelist[0] != '':
            self.data = hash_password(valuelist[0])
        elif self.data is None:
            self.data = ''

class UserView(MyModelView):

    form_columns = (
        'roles',
        'first_name',
        'last_name',
        'email',
        'password',
        'registered_on',
    )

    form_args = dict(
                registered_on=dict(default=datetime.now())
            )

    form_overrides = {
        'password': AdminPasswordField,
    }