您现在的位置是: 网站首页 >Django >Vue+Django REST framework前后端分离生鲜电商 Django

┗━ 密码加密保存┗━ 重载create方法密码加密保存┗━ Django信号量实现用户密码加密

【Vue+DRF生鲜电商】15.用户注册使用信号量实现密码加密

admin2019年5月4日 22:25 Django | Vue 1388人已围观

Vue+Django REST framework前后端分离生鲜电商简介 Vue+Django REST framework 打造前后端分离的生鲜电商项目(慕课网视频)。 Github地址:https://github.com/xyliurui/DjangoOnlineFreshSupermarket ; Django版本:2.2、djangorestframework:3.9.2。 前端Vue模板可以直接联系我拿。

密码加密保存

重载create方法密码加密保存

所以在UserSerializer中重载create(self, validated_data)方法,添加以下代码

class UserSerializer(serializers.ModelSerializer):
    # ... 省略代码
    def create(self, validated_data):
        user = super(UserSerializer, self).create(validated_data=validated_data)  # user对象是Django中继承的AbstractUser
        # UserProfile-->AbstractUser-->AbstractBaseUser中有个set_password(self, raw_password)方法
        user.set_password(validated_data['password'])  # 取出password密码,进行加密后保存
        user.save()
        # ModelSerializer有一个save()方法,save()里面会调用create()函数,这儿重载了create()函数,加入加密的逻辑
        return user
    # ... 省略代码

测试添加数据,先删除历史的数据,在执行添加

BLOG_20190530_143705_26

BLOG_20190530_143659_24

BLOG_20190530_143653_93

现在序列化不显示密码,只会显示usernamemobile,及密码存储数据库为不可逆密文保存。

此时 user/serializers.py 中序列化类UserSerializer内容如下

class UserSerializer(serializers.ModelSerializer):
    code = serializers.CharField(required=True,
                                 min_length=4,
                                 max_length=4,
                                 help_text='验证码',
                                 label='验证码',
                                 write_only=True,  # 更新或创建实例时可以使用该字段,但序列化时不包含该字段
                                 error_messages={
                                     'blank': '请输入验证码',
                                     'required': '该字段必填项',
                                     'min_length': '验证码格式不正确',
                                     'max_length': '验证码格式不正确',
                                 })
    username = serializers.CharField(required=True,
                                     allow_blank=False,
                                     help_text='用户名',
                                     label='用户名',
                                     validators=[UniqueValidator(queryset=User.objects.all(), message='用户已存在')])
    password = serializers.CharField(required=True,
                                     help_text='密码',
                                     label='密码',
                                     write_only=True,
                                     style={'input_type': 'password'})

    def validate_code(self, code):
        # 验证code
        # self.initial_data 为用户前端传过来的所有值
        verify_codes = VerifyCode.objects.filter(mobile=self.initial_data['username']).order_by('-add_time')
        if verify_codes:
            last_record = verify_codes[0]

            # 发送验证码如果超过某个时间就提示过期
            three_minute_ago = now() - timedelta(hours=0, minutes=3, seconds=0)  # 获取三分钟以前的时间
            if last_record.add_time < three_minute_ago:
                #            3ago             now
                #      add1          add2            add1就过期
                raise serializers.ValidationError('验证码已过期')

            # 比较传入的验证码
            if last_record.code != code:
                raise serializers.ValidationError('验证码输入错误')
            # return code
            # 这没必要return,因为code这个字段只是用来验证的,不是用来保存到数据库中的

        else:
            # 没有查到该手机号对应的验证码
            raise serializers.ValidationError('验证码错误')

    def validate(self, attrs):
        """
        code 这个字段是不需要保存数据库的,不需要改字段
        validate这个函数作用于所有的字段之上
        :param attrs: 每个字段validate之后返回的一个总的dict
        :return:
        """
        attrs['mobile'] = attrs['username']  # mobile不需要前端传过来,就直接后台取username中的值填充
        del attrs['code']  # 删除不需要的code字段
        return attrs

    def create(self, validated_data):
        user = super(UserSerializer, self).create(validated_data=validated_data)  # user对象是Django中继承的AbstractUser
        # UserProfile-->AbstractUser-->AbstractBaseUser中有个set_password(self, raw_password)方法
        user.set_password(validated_data['password'])  # 取出password密码,进行加密后保存
        user.save()
        # ModelSerializer有一个save()方法,save()里面会调用create()函数,这儿重载了create()函数,加入加密的逻辑
        return user

    class Meta:
        model = User
        fields = ('username', 'mobile', 'code', 'password')  # username是Django自带的字段,与mobile的值保持一致

Django信号量实现用户密码加密

UserSerializer中,能否不加入以下逻辑,或者说不重载create()方法实现密码加密功能

class UserSerializer(serializers.ModelSerializer):
    # ...省略代码
    def create(self, validated_data):
        user = super(UserSerializer, self).create(validated_data=validated_data)  # user对象是Django中继承的AbstractUser
        # UserProfile-->AbstractUser-->AbstractBaseUser中有个set_password(self, raw_password)方法
        user.set_password(validated_data['password'])  # 取出password密码,进行加密后保存
        user.save()
        # ModelSerializer有一个save()方法,save()里面会调用create()函数,这儿重载了create()函数,加入加密的逻辑
        return user
    # ...省略代码

是否可以写到另一个分离的地方。可以使用Django的信号量。

可以参考Django的信号: https://docs.djangoproject.com/zh-hans/2.2/topics/signals/

Django包含一个“信号调度器”,它允许在框架的其他地方发生操作时通知已解耦的应用程序。简而言之,信号允许某些发送方通知一组接收方某些操作已经发生。当许多代码段可能对相同的事件感兴趣时,它们尤其有用。

Django发送的所有信号的列表。所有内置信号都使用send()方法发送。 https://docs.djangoproject.com/zh-hans/2.2/ref/signals/

在DRF也有处理信号的,参考 https://www.django-rest-framework.org/api-guide/authentication/#by-using-signals ,在示例中,如果希望每个用户都有一个自动生成的令牌,只需捕获用户的post_save信号。

在 users 应用下创建 signals.py 文件,用于保存信号函数,参考创建token信号的函数,用来在新建用户时加密密码。

首先注释掉UserSerializer序列化类中的create()函数

class UserSerializer(serializers.ModelSerializer):
    # ...省略代码

    # def create(self, validated_data):
    #     user = super(UserSerializer, self).create(validated_data=validated_data)  # user对象是Django中继承的AbstractUser
    #     # UserProfile-->AbstractUser-->AbstractBaseUser中有个set_password(self, raw_password)方法
    #     user.set_password(validated_data['password'])  # 取出password密码,进行加密后保存
    #     user.save()
    #     # ModelSerializer有一个save()方法,save()里面会调用create()函数,这儿重载了create()函数,加入加密的逻辑
    #     return user

改用信号来完成,编辑 signals.py 文件

from django.conf import settings
from django.db.models.signals import post_save
from django.dispatch import receiver

from django.contrib.auth import get_user_model

User = get_user_model()


@receiver(post_save, sender=settings.AUTH_USER_MODEL)
def create_user(sender, instance=None, created=False, **kwargs):
    if created:
        password = instance.password  # instance指的就是创建的用户对象
        instance.set_password(password)
        instance.save()

settings.AUTH_USER_MODEL可以直接用User表示。

sender表示接收User这个Model传递过来的信号,在传过来后,它需要确认是否是created新建数据,如果是新建数据,才进行密码加密。因为如果是update更新的时候也会传递post_save信号。使用信号,代码分离性较强。

这些逻辑写完之后还需要加个配置,修改 users/apps.py 重载UsersConfigready方法

from django.apps import AppConfig


class UsersConfig(AppConfig):
    name = 'users'
    verbose_name = '用户'

    def ready(self):
        from users.signals import create_user

BLOG_20190530_143640_13

BLOG_20190530_143628_39

BLOG_20190530_143623_18

恢复运行,可以得到返回的序列化数据

BLOG_20190530_143612_49

在后台也可以看到已加密的密码

BLOG_20190530_143606_89

很赞哦! (0)

文章交流

  • emoji
0人参与,0条评论

当前用户

未登录,点击   登录

站点信息

  • 建站时间:网站已运行2421天
  • 系统信息:Linux
  • 后台程序:Python: 3.8.10
  • 网站框架:Django: 3.2.6
  • 文章统计:257 篇
  • 文章评论:63 条
  • 腾讯分析网站概况-腾讯分析
  • 百度统计网站概况-百度统计
  • 公众号:微信扫描二维码,关注我们
  • QQ群:QQ加群,下载网站的学习源码
返回
顶部
标题 换行 登录
网站