jwt自定义表签发、jwt多方式登录(auth的user表)

发布时间 2023-09-11 20:23:46作者: 别管鱼油我了

jwt自定义表签发

继承AbstractUser,直接使用自动签发token

纯自己写的用户表,需要自己签发

关于签发:

  1、通过user生成payload,jwt提供的方法,字段必须是username,传入user,返回payload

  2、生成token,jwt提供的方法,把payload放入token

自定义表大致流程:

  先创建表需要什么建什么,在视图类中获取前端传入的用户名和密码,判断是否登录,如果登陆了就签发,没登录就返回未登录信息。在签发中,jwt提供的方法,通过user生成payload,把payload放入token,生成token,返回登录成功信息及token等。

 

进入rest_framework_jwt.源码,齿轮中找到views

 序列化类中

 视图类:

 路由:

 模型:

关于迁移过表了,存在auth的user表了,再继承AbstractUser,再写用户表的报错,解决方案

1、以后尽量不这么写,在扩写auth的user表,一开始就扩写,不要等迁移完了之后扩写

2、删库

3、删迁移文件(不要删__init__.py和migrations文件夹)

  项目app的迁移文件

  django内置app的admin和auth的迁移文件

4、重新迁移两个命令

5、扩写auth的user表,需要在配置文件配置

从admin进入源码:

删除admin下的migrations(除了init)

删除auth下的migrations(除了init)

别忘了删除app01下的migrations

 注册从AbstractUser找源码:

 注册:

 

jwt多种方式登录(auth的user表)

多种登录方式是无论使用用户名+密码,还是邮箱+密码,还是手机号+密码都可以登录,他们都以username的形式提交给后端。

流程:

  序列化类中:序列化,反序列化,数据校验,在这里只需要做数据校验

  前端传过来的username和password字段要校验

  视图类执行is.valid(),这里username过不了因为这里有unique,需要重写username

   然后走全局钩子,全局钩子里进行校验

      并且在全局钩子里分了两个方法,在后续修改的时候方便

      第一个方法是_get_user:多方式的登录,以后改成单方式登录,只需要修改这里即可

      第二个方法是_get_token:用第三方签发,后期改成自己的签发,只需要改它即可

      把生成的token和用户名放到序列化类中,但是怕污染数据,将它放到了序列化类的对象context中

      从视图类取的时候也以字典形式取。

上面为什么用_来隐藏方法,正常在类的内部是用__(两个_)来表示隐藏,但是现在约定俗称以_开头,表示只在类内部使用,不给外部使用,但外部使用也可直接用

 普通方法:

视图类:

from rest_framework.viewsets import GenericViewSet
import re
from .models import Authuser
from rest_framework.decorators import action
#不用序列化的普通方法

class UserView(GenericViewSet):
    @action(methods=['POST'],detail=False)
    def login(self,request):
        username = request.data.get('username')
        password = request.data.get('password')
        #判断用户名是和哪个匹配
        if re.match(r'^1[3-9][0-9]{9}$', username):
            user = Authuser.objects.filter(phone=username).first()
        elif re.match(r'^.+@.+$', username):
            user = Authuser.objects.filter(email=username).first()
        else:
            user = Authuser.objects.filter(username=username).first()

        #密码进行加密
        if user and user.check_password(password):
            payload = jwt_payload_handler(user)
            token = jwt_encode_handler(payload)
            return Response({'code':100,'msg':'登录成功','token':token,'username':user.username})
        else:
            return Response({'code': 111, 'msg': '用户名或密码错误'})

路由:

 第二种:

需要写序列化类的方法,优点可扩展性强

视图类:

 序列化类:

from rest_framework import serializers
from .models import Authuser
import re
from rest_framework_jwt.settings import api_settings
jwt_payload_handler = api_settings.JWT_PAYLOAD_HANDLER
jwt_encode_handler = api_settings.JWT_ENCODE_HANDLER
from rest_framework.exceptions import ValidationError
class Loginserializer(serializers.ModelSerializer):
    username = serializers.CharField()
    class Meta:
        model = Authuser
        fields = ['username','password']

    def _get_user(self,attrs):
        username = attrs.get('username')
        password = attrs.get('password')
        if re.match(r'^1[3-9][0-9]{9}$', username):
            user = Authuser.objects.filter(phone=username).first()
        elif re.match(r'^.+@.+$', username):
            user = Authuser.objects.filter(email=username).first()
        else:
            user = Authuser.objects.filter(username=username).first()

        if user and user.check_password(password):
            return user
        else:
            raise ValidationError('用户名或密码错误')
    def _get_token(self,user):
        payload = jwt_payload_handler(user)
        token = jwt_encode_handler(payload)
        return token


    def validate(self, attrs):
        user = self._get_user(attrs)
        token = self._get_token(user)
        self.context['token'] =token
        self.context['username'] = user.username
        return attrs