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

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

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

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)`方法,添加以下代码 ```python 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](/media/blog/images/2019/05/BLOG_20190530_143705_26.png "博客图集BLOG_20190530_143705_26.png") ![BLOG_20190530_143659_24](/media/blog/images/2019/05/BLOG_20190530_143659_24.png "博客图集BLOG_20190530_143659_24.png") ![BLOG_20190530_143653_93](/media/blog/images/2019/05/BLOG_20190530_143653_93.png "博客图集BLOG_20190530_143653_93.png") 现在序列化不显示密码,只会显示`username`、`mobile`,及密码存储数据库为不可逆密文保存。 此时 user/serializers.py 中序列化类`UserSerializer`内容如下 ```python 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()`方法实现密码加密功能 ```python 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()函数 ```python 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 文件 ```python 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 重载`UsersConfig`的`ready`方法 ```python 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](/media/blog/images/2019/05/BLOG_20190530_143640_13.png "博客图集BLOG_20190530_143640_13.png") ![BLOG_20190530_143628_39](/media/blog/images/2019/05/BLOG_20190530_143628_39.png "博客图集BLOG_20190530_143628_39.png") ![BLOG_20190530_143623_18](/media/blog/images/2019/05/BLOG_20190530_143623_18.png "博客图集BLOG_20190530_143623_18.png") 恢复运行,可以得到返回的序列化数据 ![BLOG_20190530_143612_49](/media/blog/images/2019/05/BLOG_20190530_143612_49.png "博客图集BLOG_20190530_143612_49.png") 在后台也可以看到已加密的密码 ![BLOG_20190530_143606_89](/media/blog/images/2019/05/BLOG_20190530_143606_89.png "博客图集BLOG_20190530_143606_89.png")

很赞哦! (0)

文章交流

  • emoji
0人参与,0条评论

当前用户

未登录,点击   登录

站点信息

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