Flask 管理员在更改用户模型时覆盖密码
Flask admin overrides password when user model is changed
我目前正在研究一个 flask 项目,第一次尝试使用 flask-admin。到目前为止一切正常,但有一件事真正困扰我:
每当我编辑我的用户模型时,用户密码都会被覆盖。我遵循 的第二个答案中给出的建议,以防止 flask-admin 重新散列我的密码。不幸的是,清空的密码字段仍会写入数据库。
我试图从 User
-Model 获取当前密码,它作为 on_model_change
方法的参数给出,但不知何故密码似乎已经在那个时候被覆盖(或这不是我在这里看到的实际数据库模型 - 我在这里有点困惑)。
我的代码如下所示:
用户模型
class User(UserMixin, SurrogatePK, Model):
"""A user of the app."""
__tablename__ = 'users'
username = Column(db.String(80), unique=True, nullable=False)
email = Column(db.String(80), unique=True, nullable=False)
#: The hashed password
password = Column(db.String(128), nullable=True)
created_at = Column(db.DateTime, nullable=False,
default=datetime.datetime.utcnow)
first_name = Column(db.String(30), nullable=True)
last_name = Column(db.String(30), nullable=True)
active = Column(db.Boolean(), default=False)
is_admin = Column(db.Boolean(), default=False)
def __init__(self, username="", email="", password=None, **kwargs):
"""Create instance."""
db.Model.__init__(self, username=username, email=email, **kwargs)
if password:
self.set_password(password)
else:
self.password = None
def __str__(self):
"""String representation of the user. Shows the users email address."""
return self.email
def set_password(self, password):
"""Set password"""
self.password = bcrypt.generate_password_hash(password)
def check_password(self, value):
"""Check password."""
return bcrypt.check_password_hash(self.password, value)
def get_id(self):
"""Return the email address to satisfy Flask-Login's requirements"""
return self.id
@property
def full_name(self):
"""Full user name."""
return "{0} {1}".format(self.first_name, self.last_name)
@property
def is_active(self):
"""Active or non active user (required by flask-login)"""
return self.active
@property
def is_authenticated(self):
"""Return True if the user is authenticated."""
if isinstance(self, AnonymousUserMixin):
return False
else:
return True
@property
def is_anonymous(self):
"""False, as anonymous users aren't supported."""
return False
Flask-Admin 用户视图
class UserView(MyModelView):
"""Flask user model view."""
create_modal = True
edit_modal = True
def on_model_change(self, form, User, is_created):
if form.password.data is not None:
User.set_password(form.password.data)
else:
del form.password
def on_form_prefill(self, form, id):
form.password.data = ''
非常感谢任何帮助。
提前致谢,
奥尼罗
覆盖 get_edit_form
方法并从编辑表单中完全删除密码字段可能更容易。
class UserView(MyModelView):
def get_edit_form(self):
form_class = super(UserView, self).get_edit_form()
del form_class.password
return form_class
另一种方法是从表单中完全删除模型密码字段,并使用一个虚拟密码字段,然后可用于填充模型密码。通过删除真实的密码字段,Flask-Admin 将不会踩到我们的密码数据。示例:
class UserView(MyModelView):
form_excluded_columns = ('password')
# Form will now use all the other fields in the model
# Add our own password form field - call it password2
form_extra_fields = {
'password2': PasswordField('Password')
}
# set the form fields to use
form_columns = (
'username',
'email',
'first_name',
'last_name',
'password2',
'created_at',
'active',
'is_admin',
)
def on_model_change(self, form, User, is_created):
if form.password2.data is not None:
User.set_password(form.password2.data)
我遇到过类似的问题。当密码字段被更改时,我需要生成密码的哈希值。我不想添加额外的表格来更改密码。在后端,我使用了 MongoDB。我对烧瓶管理员的解决方案:
class User(db.Document, UserMixin):
***
password = db.StringField(verbose_name='Password')
roles = db.ListField(db.ReferenceField(Role), default=[]
def save(self) -> None:
if not self.id:
self.password = hashlib.md5((self.password + Config.SECURITY_PASSWORD_SALT).encode()).hexdigest()
return super(User, self).save(self)
else:
return super(User, self).update(
***
password = self.password,
)
class UserModelView(ModelView):
def on_model_change(self, form, model, is_created):
user = User.objects(id=model.id)[0]
if user.password != form.password.data:
model.password = hashlib.md5((form.password.data + Config.SECURITY_PASSWORD_SALT).encode()).hexdigest()
admin.add_view(UserModelView(User, 'Users'))
对于 SQL 的解决方案,它也将是实际的。
我目前正在研究一个 flask 项目,第一次尝试使用 flask-admin。到目前为止一切正常,但有一件事真正困扰我:
每当我编辑我的用户模型时,用户密码都会被覆盖。我遵循
我试图从 User
-Model 获取当前密码,它作为 on_model_change
方法的参数给出,但不知何故密码似乎已经在那个时候被覆盖(或这不是我在这里看到的实际数据库模型 - 我在这里有点困惑)。
我的代码如下所示:
用户模型
class User(UserMixin, SurrogatePK, Model):
"""A user of the app."""
__tablename__ = 'users'
username = Column(db.String(80), unique=True, nullable=False)
email = Column(db.String(80), unique=True, nullable=False)
#: The hashed password
password = Column(db.String(128), nullable=True)
created_at = Column(db.DateTime, nullable=False,
default=datetime.datetime.utcnow)
first_name = Column(db.String(30), nullable=True)
last_name = Column(db.String(30), nullable=True)
active = Column(db.Boolean(), default=False)
is_admin = Column(db.Boolean(), default=False)
def __init__(self, username="", email="", password=None, **kwargs):
"""Create instance."""
db.Model.__init__(self, username=username, email=email, **kwargs)
if password:
self.set_password(password)
else:
self.password = None
def __str__(self):
"""String representation of the user. Shows the users email address."""
return self.email
def set_password(self, password):
"""Set password"""
self.password = bcrypt.generate_password_hash(password)
def check_password(self, value):
"""Check password."""
return bcrypt.check_password_hash(self.password, value)
def get_id(self):
"""Return the email address to satisfy Flask-Login's requirements"""
return self.id
@property
def full_name(self):
"""Full user name."""
return "{0} {1}".format(self.first_name, self.last_name)
@property
def is_active(self):
"""Active or non active user (required by flask-login)"""
return self.active
@property
def is_authenticated(self):
"""Return True if the user is authenticated."""
if isinstance(self, AnonymousUserMixin):
return False
else:
return True
@property
def is_anonymous(self):
"""False, as anonymous users aren't supported."""
return False
Flask-Admin 用户视图
class UserView(MyModelView):
"""Flask user model view."""
create_modal = True
edit_modal = True
def on_model_change(self, form, User, is_created):
if form.password.data is not None:
User.set_password(form.password.data)
else:
del form.password
def on_form_prefill(self, form, id):
form.password.data = ''
非常感谢任何帮助。 提前致谢,
奥尼罗
覆盖 get_edit_form
方法并从编辑表单中完全删除密码字段可能更容易。
class UserView(MyModelView):
def get_edit_form(self):
form_class = super(UserView, self).get_edit_form()
del form_class.password
return form_class
另一种方法是从表单中完全删除模型密码字段,并使用一个虚拟密码字段,然后可用于填充模型密码。通过删除真实的密码字段,Flask-Admin 将不会踩到我们的密码数据。示例:
class UserView(MyModelView):
form_excluded_columns = ('password')
# Form will now use all the other fields in the model
# Add our own password form field - call it password2
form_extra_fields = {
'password2': PasswordField('Password')
}
# set the form fields to use
form_columns = (
'username',
'email',
'first_name',
'last_name',
'password2',
'created_at',
'active',
'is_admin',
)
def on_model_change(self, form, User, is_created):
if form.password2.data is not None:
User.set_password(form.password2.data)
我遇到过类似的问题。当密码字段被更改时,我需要生成密码的哈希值。我不想添加额外的表格来更改密码。在后端,我使用了 MongoDB。我对烧瓶管理员的解决方案:
class User(db.Document, UserMixin):
***
password = db.StringField(verbose_name='Password')
roles = db.ListField(db.ReferenceField(Role), default=[]
def save(self) -> None:
if not self.id:
self.password = hashlib.md5((self.password + Config.SECURITY_PASSWORD_SALT).encode()).hexdigest()
return super(User, self).save(self)
else:
return super(User, self).update(
***
password = self.password,
)
class UserModelView(ModelView):
def on_model_change(self, form, model, is_created):
user = User.objects(id=model.id)[0]
if user.password != form.password.data:
model.password = hashlib.md5((form.password.data + Config.SECURITY_PASSWORD_SALT).encode()).hexdigest()
admin.add_view(UserModelView(User, 'Users'))
对于 SQL 的解决方案,它也将是实际的。