Flask Admin - 创建新用户时自动创建密码哈希?
Flask Admin - Automatically create password hash when creating a new user?
假设我有这样一个用户模型:
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 的东西自动生成密码哈希?
您可以使用 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()
我认为自动是指它应该自动将 manually-supplied plain-text 密码转换为散列,但我不确定。我的回答好像这个假设是正确的。
我们不会在 Flask-Admin 中公开我们的密码字段,但我们通过将 password
定义为带有 属性 来处理如何以及何时对密码进行哈希处理的基本问题=50=] 负责计算哈希本身并将其隐藏在 user._password
.
中
尝试将 password
添加为管理视图中的列的天真尝试不起作用,但是如果您使用 sqlalchemy 的 hybrid_property
而不是 property
,它看起来像这样在您的用户视图的 form_columns
列表中使用 "password"
效果很好(因为您已经拥有):
# models.py
from sqlalchemy.ext.hybrid import hybrid_property
class User(sql.Model):
# ...
_password = sql.Column(sql.Binary)
_salt = sql.Column(sql.Binary, default=lambda: 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", ...)
编辑体验并不完美——您可能需要重写该字段以优化它。以下是一些截图:
正在使用 pre-set 密码创建新用户:
创建后的编辑视图:
更新用户密码:
保存新密码后的编辑视图:
我发现的最简单的选择是在 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
在内部,Flask-Admin
调用 WTF
的 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
中使用了,如下:
class UserView(ModelView):
form_extra_fields = {
'password': CustomPasswordField('Password', validators=[InputRequired()])
}
密码将在保存表单时进行哈希处理。
您可以为 password
字段设置一个 PasswordField
小部件,并覆盖 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,
}
假设我有这样一个用户模型:
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 的东西自动生成密码哈希?
您可以使用 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()
我认为自动是指它应该自动将 manually-supplied plain-text 密码转换为散列,但我不确定。我的回答好像这个假设是正确的。
我们不会在 Flask-Admin 中公开我们的密码字段,但我们通过将 password
定义为带有 属性 来处理如何以及何时对密码进行哈希处理的基本问题=50=] 负责计算哈希本身并将其隐藏在 user._password
.
尝试将 password
添加为管理视图中的列的天真尝试不起作用,但是如果您使用 sqlalchemy 的 hybrid_property
而不是 property
,它看起来像这样在您的用户视图的 form_columns
列表中使用 "password"
效果很好(因为您已经拥有):
# models.py
from sqlalchemy.ext.hybrid import hybrid_property
class User(sql.Model):
# ...
_password = sql.Column(sql.Binary)
_salt = sql.Column(sql.Binary, default=lambda: 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", ...)
编辑体验并不完美——您可能需要重写该字段以优化它。以下是一些截图:
正在使用 pre-set 密码创建新用户:
创建后的编辑视图:
更新用户密码:
保存新密码后的编辑视图:
我发现的最简单的选择是在 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
在内部,Flask-Admin
调用 WTF
的 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
中使用了,如下:
class UserView(ModelView):
form_extra_fields = {
'password': CustomPasswordField('Password', validators=[InputRequired()])
}
密码将在保存表单时进行哈希处理。
您可以为 password
字段设置一个 PasswordField
小部件,并覆盖 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, }