博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Vue + Django 2.0.6 学习笔记 7.12-13信号量实现用户密码修改,vue和注册功能联调
阅读量:4127 次
发布时间:2019-05-25

本文共 6386 字,大约阅读时间需要 21 分钟。

首先先设置queryset字段

# users/views.pyclass UserViewset(CreateModelMixin, viewsets.GenericViewSet):    queryset = User.objects.all()

测试注册的时候出现该错误

报这个错的原因是

我们配置的字段是fields = ("username", "code", "mobile", "password")

但是我们在代码中已经删掉了code字段。所以 返回的时候是将这几个字段都序列化返回到前端的

# 继承关系from rest_framework.mixins import CreateModelMixinclass UserViewset(CreateModelMixin, viewsets.GenericViewSet):class CreateModelMixin:    # 看截图

所以我们需要在自定义的字段校验中加入write_only= True

class UserRegSerializer(serializers.ModelSerializer):    code = serializers.CharField(required=True, max_length=4, min_length=4, write_only=True, label='验证码',                                 error_messages={                                     "blank":"请输入验证码",                                   "required":"请输入验证码",                                    "max_length":"验证码格式错误",                                     "min_length":"验证码格式错误"                                 },                                 help_text="验证码")

设置rest_api接口测试页面的密码输入为password类型:

password = serializers.CharField(                                                      # 返回的时候也不显示密码         style={'input_type': 'password'}, label='密码', write_only=True    )

效果

接下来的问题:

密码明文存储

正常情况下 ModelSerializer是明文存储密码的 所以需要自定义pasword的存储

那怎么搞?

重写create函数from rest_framework import serializers / Serializer / BaseSerializer    def create(self, validated_data):        user = super(UserRegSerializer, self).create(validated_data=validated_data)        user.set_password(validated_data['password'])        user.save()        return user

如果觉得这样写 改变了框架代码  可以这么干

使用信号量机制

参考文档

django:

rest_framework:

类似于QT的信号槽  Vue的父子组件信号传递

 

使用方法

# 在usersapp下新建signals.pyfrom django.db.models.signals import post_savefrom django.dispatch import receiverfrom rest_framework.authtoken.models import Tokenfrom django.contrib.auth import get_user_modelUser = get_user_model()#第一个参数是信号量名称, 第二个是哪个model接收信号@receiver(post_save, sender=User)def create_auth_token(sender, instance=None, created=False, **kwargs):    # 判断是否新建    if created:        password = instance.password        instance.set_password(password)        instance.save()

然后在apps.py中添加

from django.apps import AppConfigclass UsersConfig(AppConfig):    name = 'users'    verbose_name = '用户'    def ready(self):        import users.signals

在前端注册成功后会有两种机制

一种是需要用户登录 一种是自动登录转主页

第一种不说 直接跳转主页就可以了

第二种需要token 

所以如果是第二种我们就需要返回token给前端

实现:

 

# 重写CreateModelMixin/create函数# 原始函数的代码class CreateModelMixin(object):    """    Create a model instance.    """    def create(self, request, *args, **kwargs):        serializer = self.get_serializer(data=request.data)        serializer.is_valid(raise_exception=True)        self.perform_create(serializer)        headers = self.get_success_headers(serializer.data)        return Response(serializer.data, status=status.HTTP_201_CREATED, headers=headers)    def perform_create(self, serializer):        serializer.save()

这里的perform中的save是save了当前的model(user)。但是并没有返回该model。我们要想获取到user model 就必须重写让它返回model

然后在执行perform_create之后插入我们自己的逻辑。

分析jwt的源码实现,找到它哪部分才是生成token的。

- 从url入口。点进obtain_jwt_token

path('login/', obtain_jwt_token )obtain_jwt_token = ObtainJSONWebToken.as_view()class ObtainJSONWebToken(JSONWebTokenAPIView):    """    API View that receives a POST with a user's username and password.    Returns a JSON Web Token that can be used for authenticated requests.    """    serializer_class = JSONWebTokenSerializer

此时我们就可以去查看继承的父类: JSONWebTokenAPIView

该类中用户在post数据过来之后。

def post(self, request, *args, **kwargs):        serializer = self.get_serializer(data=request.data)        if serializer.is_valid():            user = serializer.object.get('user') or request.user            token = serializer.object.get('token')            response_data = jwt_response_payload_handler(token, user, request)            response = Response(response_data)            if api_settings.JWT_AUTH_COOKIE:                expiration = (datetime.utcnow() +                              api_settings.JWT_EXPIRATION_DELTA)                response.set_cookie(api_settings.JWT_AUTH_COOKIE,                                    token,                                    expires=expiration,                                    httponly=True)            return response        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

关键在于token是直接从Serializer中获取的,那么token的生成应该是在Serializer中实现的。

token = serializer.object.get('token')

寻找我们的Serializer

serializer = self.get_serializer(data=request.data)    def get_serializer(self, *args, **kwargs):        serializer_class = self.get_serializer_class()       	return self.serializer_class

Serializer位于rest_framework_jwt/views.py的ObtainJSONWebToken类中

serializer_class = JSONWebTokenSerializer
payload = jwt_payload_handler(user)                return {                    'token': jwt_encode_handler(payload),                    'user': user                }

调用了jwt_encode_handler, 而该handler是api_setting中设置的

jwt_payload_handler = api_settings.JWT_PAYLOAD_HANDLERjwt_encode_handler = api_settings.JWT_ENCODE_HANDLER

rest_framework_jwt/settings.py:

DEFAULTS = {    'JWT_ENCODE_HANDLER':    'rest_framework_jwt.utils.jwt_encode_handler',      'JWT_PAYLOAD_HANDLER':    'rest_framework_jwt.utils.jwt_payload_handler',    }

所以我们已经找到了生成token的两个重要步骤,一payload,二encode

实现代码:

def create(self, request, *args, **kwargs):        serializer = self.get_serializer(data=request.data)        serializer.is_valid(raise_exception=True)        user = self.perform_create(serializer)        re_dict = serializer.data        payload = jwt_payload_handler(user)        re_dict["token"] = jwt_encode_handler(payload)        re_dict['name'] = user.name if user.name else user.username        headers = self.get_success_headers(serializer.data)        return Response(re_dict, status=status.HTTP_201_CREATED, headers=headers)

其中的token要和前端保持一致。注意将原本返回的Serializer.data进行加工之后返回。

 

退出功能:

// Vue中 login.ue退出// head.vue        loginOut(){            cookie.delCookie('token');            cookie.delCookie('name');            this.$store.dispatch('setInfo');            // this.$http.get('/getMenu')            //     .then((response)=> {                    //跳转到登录                    this.$router.push({ name: 'login' })            //     })            //     .catch(function (error) {            //       console.log(error);            // });        },

清空token给axios发一个通知。跳转到登录页面。

第七章完结 内容多 且比较绕 估计以后要回来重新瞅好几次

完结

部分内容参考天涯明月笙大佬  

转载地址:http://piepi.baihongyu.com/

你可能感兴趣的文章
「译」在 python 中,如果 x 是 list,为什么 x += "ha" 可以运行,而 x = x + "ha" 却抛出异常呢?...
查看>>
浅谈JavaScript的语言特性
查看>>
LeetCode第39题思悟——组合总和(combination-sum)
查看>>
LeetCode第43题思悟——字符串相乘(multiply-strings)
查看>>
LeetCode第44题思悟——通配符匹配(wildcard-matching)
查看>>
LeetCode第45题思悟——跳跃游戏(jump-game-ii)
查看>>
LeetCode第46题思悟——全排列(permutations)
查看>>
LeetCode第47题思悟—— 全排列 II(permutations-ii)
查看>>
LeetCode第48题思悟——旋转图像(rotate-image)
查看>>
驱动力3.0,动力全开~
查看>>
记CSDN访问量10万+
查看>>
Linux下Oracle数据库账户被锁:the account is locked问题的解决
查看>>
记CSDN访问20万+
查看>>
Windows 环境下Webstorm 2020.3 版本在右下角找不到Git分支切换部件的一种解决方法
查看>>
Electron-Vue项目中遇到fs.rm is not a function问题的解决过程
查看>>
飞机换乘次数最少问题的两种解决方案
查看>>
有向无回路图的理解
查看>>
设计模式中英文汇总分类
查看>>
WPF实现蜘蛛纸牌游戏
查看>>
单例模式
查看>>