You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Django REST Framework:PUT/PATCH请求密码未加密问题及解决方法

问题分析与解决方案

嘿,这个问题我之前也踩过坑,咱一步步来拆解清楚:

为什么密码会明文保存?

核心原因是Django自带的User模型(或你继承的AbstractUser)必须通过set_password()方法设置密码——这个方法会自动把明文密码哈希成Django认证系统能识别的加密格式。而你用的ModelSerializer默认的update()方法只是简单地将验证后的数据直接赋值给模型实例字段,也就是直接执行instance.password = validated_data['password'],完全不会调用set_password(),所以密码就以明文存在数据库里了。

另外看你当前的序列化器,fields里并没有包含password字段,这说明你可能是通过请求体直接传了password参数(DRF默认允许传递额外字段,或者你后来调整过配置),但不管怎样,默认的更新逻辑都不会处理密码加密这一步。

该如何修复?重写Serializer还是ViewSet的update?

肯定是重写Serializer的update()方法,这才符合DRF的设计逻辑:序列化器负责处理数据的验证、模型实例的创建与更新,而ViewSet只负责处理请求流程(比如路由匹配、获取实例、返回响应)。把密码加密的逻辑放在序列化器里,后续如果其他地方复用这个序列化器(比如创建用户),也能自动复用加密逻辑,更灵活也更符合职责分离的原则。

具体修复代码

首先,先把password字段加到序列化器里,并且设置为只写字段(避免响应里返回密码,这是安全规范):

from rest_framework import serializers
from django.contrib.auth.models import User

class UserSerializer(serializers.ModelSerializer):
    class Meta:
        model = User
        fields = ('url', 'username', 'email', 'pk', 'password')
        # 设置密码为只写字段,前端只能传入,不能从响应中获取
        extra_kwargs = {
            'password': {'write_only': True}
        }

    def update(self, instance, validated_data):
        # 先从验证数据里取出密码(如果请求中传了的话)
        password = validated_data.pop('password', None)
        # 调用父类的update方法处理其他常规字段(比如username、email)
        user = super().update(instance, validated_data)
        
        # 如果有要更新的密码,调用set_password加密后保存
        if password:
            user.set_password(password)
            user.save()
        
        return user

如果你的业务还需要支持创建用户(POST请求),记得也要重写序列化器的create()方法,不然创建用户时密码也会明文保存:

def create(self, validated_data):
        # 取出密码
        password = validated_data.pop('password')
        # 创建用户实例,但先不直接设置密码
        user = User(**validated_data)
        # 调用set_password加密密码
        user.set_password(password)
        user.save()
        return user

总结问题点

  1. 你没有在序列化器中处理User模型的密码加密逻辑,默认的ModelSerializer不知道要调用set_password()来加密密码
  2. 即使你没把password放进序列化器的fields,如果请求里传了这个参数,默认更新逻辑还是会直接赋值,跳过加密步骤
  3. 正确的姿势是把加密逻辑放在序列化器的update()和create()方法里,这是序列化器的职责范围

内容的提问来源于stack exchange,提问作者vixrant

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.21 07:19:27