Django Admin 使用 save_model() 在更改(或保存)时加密某些字段的值
Django Admin encrypt values of certain fields on changed(or save) with save_model()
我目前有一个自定义用户模型,其中一些字段应该被加密(数据端),但在 Django Admin 上,它们需要被解密以显示实际数据,所以我有 encrypt_string()
和 decrypt_string()
函数来处理它。
我的用户模型:
class User(AbstractUser):
uid = models.CharField(
"uid", max_length=255, null=True, blank=True)
nickname = models.CharField(
"Nickname", max_length=255, null=True, blank=True)
eth_address = models.CharField(
"Eth address", max_length=255, null=True, blank=True)
eth_private_key = models.CharField(
"Eth private key", max_length=255, null=True, blank=True)
evt_address = models.CharField(
"Evt address", max_length=255, null=True, blank=True)
evt_private_key = models.CharField(
"Evt private key", max_length=255, null=True, blank=True)
eth_address、eth_private_key、evt_address 和 evt_private_key 在进行任何类型的保存或编辑时都需要加密
当前,当我的服务器从 api 发出请求时,它将创建一个默认用户(在 django-rest-framework 的自定义 authentication_class 上处理):
existed_user_check = User.objects.filter(uid=uid).exists()
if not existed_user_check:
random_password = ''.join(["{}".format(randint(0, 9)) for num in range(0, 6)])
eth_address, eth_private_key = generate_eth()
evt_address, evt_private_key = generate_evt()
new_user = User(
username=uid,
uid=uid,
eth_address=encrypt_string(eth_address),
eth_private_key=encrypt_string(eth_private_key),
evt_address=encrypt_string(evt_address),
evt_private_key=encrypt_string(evt_private_key)
)
new_user.set_password(random_password)
new_user.save()
在我的 Django Admin 中,我在 admin.py 中编写了以下内容来处理解密(在更改视图中显示数据时)和加密(在对这 4 个字段进行任何保存或编辑时):
user_profile_encrypt_fields = [
'eth_address',
'eth_private_key',
'evt_address',
'evt_private_key'
]
class UserAdminForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
super(UserAdminForm, self).__init__(*args, **kwargs)
for field in user_profile_encrypt_fields:
if getattr(self.instance, field) is not None:
try:
self.initial[field] = decrypt_string(getattr(self.instance, field))
except Exception as e:
pass
class UserAdminCustom(admin.ModelAdmin):
# UserAdminForm handle decrypt data
form = UserAdminForm
exclude = ('password', 'last_login', 'is_superuser', 'is_staff', 'groups',
'user_permissions', 'username', 'first_name', 'last_name', 'is_active', 'date_joined')
def get_queryset(self, request):
qs = super(UserAdminCustom, self).get_queryset(request)
return qs.filter(is_staff=False)
def get_readonly_fields(self, request, obj=None):
return ('id', 'created', 'modified')
# save_model() handle encrypt data on saving
def save_model(self, request, obj, form, change):
for field in form.changed_data:
if form.cleaned_data.get(field) is not None:
if field in user_profile_encrypt_fields:
encrypted_value = encrypt_string(form.cleaned_data.get(field))
setattr(obj, field, encrypted_value)
obj.save()
admin.site.register(User, UserAdminCustom)
为我自定义 UserAdminForm 来解密数据,以便管理员在进行编辑或检查时可以看到它是什么。
解密后的数据能够正确显示在更改视图中
save_model() 将在管理员编辑 Django Admin 更改视图上的字段时处理数据加密。
我目前的问题:
备注:
这些字段中的数据已经存在,所以我只讨论 django admin 上的编辑对象部分。
当我尝试编辑任何字段并保存它(应该加密)时,该字段被加密并保存,但它下面的字段(它的实际加密数据)现在变成了它的实际数据(不是加密)
在更改视图上编辑 evt_address 并保存后
使用时解密数据form = UserAdminForm
在 UserAdminCustom 上注释掉 # form = UserAdminForm
以便显示实际数据
我打印出 getattr(self.instance, field)
以查看加载 django 管理更改视图时的加密数据,并得到以下 4 个加密字段:
web_1 | eth_address : gAAAAABeAcoI08bH2fQqJboZFxg6xn5RCxdRopllS6fDeyRmsC3qzsTXo88NVYOb58eeX5IXQpxqcGhbLr8wRRoWSKQsX5vLbPPhmWqUiqf0XYQvdWUhhgYxxMwwqgEOwU2OtJfkZ0p6
web_1 | eth_private_key : gAAAAABeAcoIp1V9sKNnL-dO-fWH1W1oM7hbqky44aRLchmTtvckaaZdaKuXo1xIIozx3xl40Y2Ct3YAyCOfkJJranKgTNDcVhndYdu5-awOuYpPCJKkSSia7IP_gWjLE91Gh8vsGnkn1iEkrLaho2ff0vVHS1QgGaJxji5m7cwCk0tqSp2AIeA=
web_1 | evt_address : gAAAAABeAcoIM3rywSgAPL611WUoWLJ9mqIgUHhZn8KDQd9hi9xHzgRri0EkoS_yBvwQyzdH72RWJRsDCs38oF9P8HHW_wFDWQ==
web_1 | evt_private_key : 1814067
所以我的 evt_private_key
数据在我编辑 evt_address
值并保存
后更改为 1814067
为什么会这样,我很困惑是什么原因造成的。
希望有人能帮助我
您在错误的抽象层上进行操作。
请按照本指南创建将为您处理加密/解密的自定义 Django 字段:https://docs.djangoproject.com/en/2.2/howto/custom-model-fields/
或者只使用一些现有的解决方案,例如:https://github.com/foundertherapy/django-cryptographic-fields
在多次尝试修改 save_model
函数后,我意识到表单的数据实际上来自 UserAdminForm
所以为了能够修改 django 管理表单上的数据,我需要从保存前自行形成
class UserAdminForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
super(UserAdminForm, self).__init__(*args, **kwargs)
for field in user_profile_encrypt_fields:
if getattr(self.instance, field) is not None:
try:
self.initial[field] = decrypt_string(getattr(self.instance, field))
except:
pass
def clean_eth_address(self):
if self.cleaned_data['eth_address'] is not None:
data = encrypt_string(self.cleaned_data['eth_address'])
else:
data = None
return data
def clean_eth_private_key(self):
if self.cleaned_data['eth_private_key'] is not None:
data = encrypt_string(self.cleaned_data['eth_private_key'])
else:
data = None
return data
def clean_evt_address(self):
if self.cleaned_data['evt_address'] is not None:
data = encrypt_string(self.cleaned_data['evt_address'])
else:
data = None
return data
def clean_evt_private_key(self):
if self.cleaned_data['evt_private_key'] is not None:
data = encrypt_string(self.cleaned_data['evt_private_key'])
else:
data = None
return data
现在,每当我在管理表单上进行更改时,它都会被加密
我目前有一个自定义用户模型,其中一些字段应该被加密(数据端),但在 Django Admin 上,它们需要被解密以显示实际数据,所以我有 encrypt_string()
和 decrypt_string()
函数来处理它。
我的用户模型:
class User(AbstractUser):
uid = models.CharField(
"uid", max_length=255, null=True, blank=True)
nickname = models.CharField(
"Nickname", max_length=255, null=True, blank=True)
eth_address = models.CharField(
"Eth address", max_length=255, null=True, blank=True)
eth_private_key = models.CharField(
"Eth private key", max_length=255, null=True, blank=True)
evt_address = models.CharField(
"Evt address", max_length=255, null=True, blank=True)
evt_private_key = models.CharField(
"Evt private key", max_length=255, null=True, blank=True)
eth_address、eth_private_key、evt_address 和 evt_private_key 在进行任何类型的保存或编辑时都需要加密
当前,当我的服务器从 api 发出请求时,它将创建一个默认用户(在 django-rest-framework 的自定义 authentication_class 上处理):
existed_user_check = User.objects.filter(uid=uid).exists()
if not existed_user_check:
random_password = ''.join(["{}".format(randint(0, 9)) for num in range(0, 6)])
eth_address, eth_private_key = generate_eth()
evt_address, evt_private_key = generate_evt()
new_user = User(
username=uid,
uid=uid,
eth_address=encrypt_string(eth_address),
eth_private_key=encrypt_string(eth_private_key),
evt_address=encrypt_string(evt_address),
evt_private_key=encrypt_string(evt_private_key)
)
new_user.set_password(random_password)
new_user.save()
在我的 Django Admin 中,我在 admin.py 中编写了以下内容来处理解密(在更改视图中显示数据时)和加密(在对这 4 个字段进行任何保存或编辑时):
user_profile_encrypt_fields = [
'eth_address',
'eth_private_key',
'evt_address',
'evt_private_key'
]
class UserAdminForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
super(UserAdminForm, self).__init__(*args, **kwargs)
for field in user_profile_encrypt_fields:
if getattr(self.instance, field) is not None:
try:
self.initial[field] = decrypt_string(getattr(self.instance, field))
except Exception as e:
pass
class UserAdminCustom(admin.ModelAdmin):
# UserAdminForm handle decrypt data
form = UserAdminForm
exclude = ('password', 'last_login', 'is_superuser', 'is_staff', 'groups',
'user_permissions', 'username', 'first_name', 'last_name', 'is_active', 'date_joined')
def get_queryset(self, request):
qs = super(UserAdminCustom, self).get_queryset(request)
return qs.filter(is_staff=False)
def get_readonly_fields(self, request, obj=None):
return ('id', 'created', 'modified')
# save_model() handle encrypt data on saving
def save_model(self, request, obj, form, change):
for field in form.changed_data:
if form.cleaned_data.get(field) is not None:
if field in user_profile_encrypt_fields:
encrypted_value = encrypt_string(form.cleaned_data.get(field))
setattr(obj, field, encrypted_value)
obj.save()
admin.site.register(User, UserAdminCustom)
为我自定义 UserAdminForm 来解密数据,以便管理员在进行编辑或检查时可以看到它是什么。 解密后的数据能够正确显示在更改视图中
save_model() 将在管理员编辑 Django Admin 更改视图上的字段时处理数据加密。
我目前的问题:
备注:
这些字段中的数据已经存在,所以我只讨论 django admin 上的编辑对象部分。
当我尝试编辑任何字段并保存它(应该加密)时,该字段被加密并保存,但它下面的字段(它的实际加密数据)现在变成了它的实际数据(不是加密)
在更改视图上编辑 evt_address 并保存后
使用时解密数据form = UserAdminForm
在 UserAdminCustom 上注释掉 # form = UserAdminForm
以便显示实际数据
我打印出 getattr(self.instance, field)
以查看加载 django 管理更改视图时的加密数据,并得到以下 4 个加密字段:
web_1 | eth_address : gAAAAABeAcoI08bH2fQqJboZFxg6xn5RCxdRopllS6fDeyRmsC3qzsTXo88NVYOb58eeX5IXQpxqcGhbLr8wRRoWSKQsX5vLbPPhmWqUiqf0XYQvdWUhhgYxxMwwqgEOwU2OtJfkZ0p6
web_1 | eth_private_key : gAAAAABeAcoIp1V9sKNnL-dO-fWH1W1oM7hbqky44aRLchmTtvckaaZdaKuXo1xIIozx3xl40Y2Ct3YAyCOfkJJranKgTNDcVhndYdu5-awOuYpPCJKkSSia7IP_gWjLE91Gh8vsGnkn1iEkrLaho2ff0vVHS1QgGaJxji5m7cwCk0tqSp2AIeA=
web_1 | evt_address : gAAAAABeAcoIM3rywSgAPL611WUoWLJ9mqIgUHhZn8KDQd9hi9xHzgRri0EkoS_yBvwQyzdH72RWJRsDCs38oF9P8HHW_wFDWQ==
web_1 | evt_private_key : 1814067
所以我的 evt_private_key
数据在我编辑 evt_address
值并保存
1814067
为什么会这样,我很困惑是什么原因造成的。
希望有人能帮助我
您在错误的抽象层上进行操作。
请按照本指南创建将为您处理加密/解密的自定义 Django 字段:https://docs.djangoproject.com/en/2.2/howto/custom-model-fields/
或者只使用一些现有的解决方案,例如:https://github.com/foundertherapy/django-cryptographic-fields
在多次尝试修改 save_model
函数后,我意识到表单的数据实际上来自 UserAdminForm
所以为了能够修改 django 管理表单上的数据,我需要从保存前自行形成
class UserAdminForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
super(UserAdminForm, self).__init__(*args, **kwargs)
for field in user_profile_encrypt_fields:
if getattr(self.instance, field) is not None:
try:
self.initial[field] = decrypt_string(getattr(self.instance, field))
except:
pass
def clean_eth_address(self):
if self.cleaned_data['eth_address'] is not None:
data = encrypt_string(self.cleaned_data['eth_address'])
else:
data = None
return data
def clean_eth_private_key(self):
if self.cleaned_data['eth_private_key'] is not None:
data = encrypt_string(self.cleaned_data['eth_private_key'])
else:
data = None
return data
def clean_evt_address(self):
if self.cleaned_data['evt_address'] is not None:
data = encrypt_string(self.cleaned_data['evt_address'])
else:
data = None
return data
def clean_evt_private_key(self):
if self.cleaned_data['evt_private_key'] is not None:
data = encrypt_string(self.cleaned_data['evt_private_key'])
else:
data = None
return data
现在,每当我在管理表单上进行更改时,它都会被加密