drf之jwt签发和认证

jwt自定义表签发

自定义表时,用模块实现签发

在models.py中

username必须为username

class MyUser(models.Model):
    username = models.CharField(max_length=32)
    password = models.CharField(max_length=32)
    email = models.CharField(max_length=32)
    phone = models.IntegerField(max_length=32)
    gender = models.IntegerField(choices=((1, '男'), (2, '女'), (0, '未知')))

在视图类中
from rest_framework.views import APIView
from .models import MyUser
from rest_framework.response import Response
from rest_framework_jwt.settings import api_settings

# 从rest_framework_jwt中
jwt_payload_handler = api_settings.JWT_PAYLOAD_HANDLER
jwt_encode_handler = api_settings.JWT_ENCODE_HANDLER


class UserView(APIView):
    def post(self, request):
        username = request.data.get('username')
        password = request.data.get('password')
        user = MyUser.objects.filter(username=username, password=password).first()
        if user:

			#1 通过user生成payload---》jwt 提供一个方法(username),传入user,返回payload
            payload = jwt_payload_handler(user)

			#2 生成token---》jwt提供了方法,把payload放入--》token
            token = jwt_encode_handler(payload)
            return Response({'code': 100, 'msg': '登录成功', 'token': token, 'username': user.username})
        else:
            return Response({'code': 101, 'msg': '用户密码错误'})

jwt 多方式登录

要求:

  • 用户名+密码 邮箱+密码 手机号+密码 都可以登录
    username+password
    email+password
    phone+password

无论是username,email,phone都以 username形式提交到后端

于是:从username字段中取出来的,可能是用户名,可能是邮箱,可能是密码—》都能登录成功

基于APIView用auth拓展表多登陆

class UserView(APIView):
    def post(self, request):
        username = request.data.get('username')
        password = request.data.get('password')

        # 电话号码+密码登录
        if re.match(r'^1[3-9][0-9]{9}$', username):
            user = User.objects.filter(phone=username).first()

        # 邮箱+密码登录
        elif re.match(r'^.+@.+$', username):
            user = User.objects.filter(email=username).first()

        # 用户名+密码
        else:
            user = User.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': 101, 'msg': '用户密码错误'})

使用序列化类多方式登录

在视图类中
from rest_framework.viewsets import GenericViewSet
from rest_framework.response import Response
from rest_framework.decorators import action
from .serializer import UserSerializer


class UserView(GenericViewSet):
    @action(methods=['POST'], detail=False)
    def login(self, request):
        ser = UserSerializer(data=request.data)
        if ser.is_valid():
            token = ser.context.get('token')
            username = ser.context.get('username')
            return Response({'code': 100, 'msg': '登录成功', 'token': token, 'username': username})
        else:
            return Response({'code': 101, 'msg': '用户密码错误'})

在序列化类中
from rest_framework import serializers
from .models import User, MyUser
import re
from rest_framework.exceptions import ValidationError
from rest_framework_jwt.settings import api_settings

# 从rest_framework_jwt中
jwt_payload_handler = api_settings.JWT_PAYLOAD_HANDLER
jwt_encode_handler = api_settings.JWT_ENCODE_HANDLER


class UserSerializer(serializers.ModelSerializer):
    username = serializers.CharField()

    class Meta:
        model = MyUser
        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 = User.objects.filter(phone=username).first()

        # 邮箱+密码登录
        elif re.match(r'^.+@.+$', username):
            user = User.objects.filter(email=username).first()

        # 用户名+密码
        else:
            user = User.objects.filter(username=username).first()

        if user and user.check_password(password):
            return user
        else:
            raise ValidationError('用户密码错误')

    def _get_token(self, attrs):
        payload = jwt_payload_handler(attrs)
        token = jwt_encode_handler(payload)
        return token

    def validate(self, attrs):
        user = self._get_user(attrs)
        token = self._get_token(attrs)

        self.context['token'] = token
        self.context['username'] = user.username

        return attrs

基于自定义表编写认证类

每次访问需要登录的接口,都会去查数据库
所以咱们可以做优化

  1. 自己生成一个user对象
  2. 直接返回user_id,以后用的时候,再查数据库

认证类

from rest_framework.authentication import BaseAuthentication
from rest_framework_jwt.settings import api_settings
from django.utils.translation import ugettext as _
from rest_framework.exceptions import AuthenticationFailed
from .models import MyUser
import jwt

jwt_decode_handler = api_settings.JWT_DECODE_HANDLER


class LoginAuth(BaseAuthentication):
    def authenticate(self, request):
        token = request.META.get('HTTP_TOKEN')

        try:
            payload = jwt_decode_handler(token)

            user = MyUser.objects.filter(pk=payload.get('id'))

        except jwt.ExpiredSignature:
            msg = _('Signature has expired.')
            raise AuthenticationFailed(msg)
        except jwt.DecodeError:
            msg = _('Error decoding signature.')
            raise AuthenticationFailed(msg)
        except jwt.InvalidTokenError:
            raise AuthenticationFailed('未知错误,请联系管理员')

        return user, token

视图类

from rest_framework.response import Response
from .models import Book
from rest_framework.viewsets import GenericViewSet, ModelViewSet
from rest_framework.decorators import action
from .serializer import UserSerializer, BookSerializer


class UserView(GenericViewSet):
    @action(methods=['POST'], detail=False)
    def login(self, request):
        ser = UserSerializer(data=request.data)
        if ser.is_valid():
            token = ser.context.get('token')
            username = ser.context.get('username')
            return Response({'code': 100, 'msg': '登录成功', 'token': token, 'username': username})
        else:
            return Response({'code': 101, 'msg': '用户密码错误'})


from .auth import LoginAuth


class BookView(ModelViewSet):
    authentication_classes = [LoginAuth]
    queryset = Book.objects.all()
    serializer_class = BookSerializer
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值