假设我有一个类似的用户模型:
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这样的东西自动生成密码哈希?
答案 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", ...)
编辑体验并未精确完善 - 您可能需要覆盖该字段以进行优化。以下是一些截图:
使用预设密码创建新用户:
创建后的编辑视图:
更新用户密码:
保存新密码后的编辑视图:
答案 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, }