jwt自定义表签发、jwt多方式登录(auth的user表)
jwt自定义表签发
继承AbstractUser,直接使用自动签发token
纯自己写的用户表,需要自己签发
关于签发:
1、通过user生成payload,jwt提供的方法,字段必须是username,传入user,返回payload
2、生成token,jwt提供的方法,把payload放入token
自定义表大致流程:
先创建表需要什么建什么,在视图类中获取前端传入的用户名和密码,判断是否存在该用户,如果存在了就签发,不存在就返回未登录信息。在签发中,jwt提供的方法,通过user生成payload,把payload放入token,生成token,返回登录成功信息及token等。
序列化类中
视图类:
路由:
模型:
关于迁移过表了,存在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