在前后端分离项目中,用到最常用的认证方式就是JWT方式了,关于jwt的介绍我我就不讲了,网上一搜一大堆,下面直接进入正题 前提: - 创建相关用户数据模型 - 安装djangorestframework - 序列化user模型

手写JWT方式认证

关于手写jwt,其实就是利用pyjwt生成token,通过修改rest_framework.authenticationBaseAuthentication方法完成,

安装pyjwt

pip install pyjwt

在app中创建一个authentications.py文件,修改rest_framework.authenticationBaseAuthentication方法

#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
@author: 小羊驼
@contact: wouldmissyou@163.com
@time: 2020/8/14 下午1:12
@file: authentications.py
@desc: 
"""
import jwt
import time
from django.conf import settings
from rest_framework.authentication import BaseAuthentication,get_authorization_header
from rest_framework import exceptions
from django.contrib.auth import get_user_model
from jwt.exceptions import ExpiredSignatureError
User = get_user_model()

def generate_jwt(user):
    expire_time = time.time() + 60*60*24*7
    return jwt.encode({"userid":user.pk,"exp":expire_time},key=settings.SECRET_KEY).decode('utf-8')


class JWTAuthentication(BaseAuthentication):
    keyword = 'JWT'
    def authenticate(self, request):
        auth = get_authorization_header(request).split()

        if not auth or auth[0].lower() != self.keyword.lower().encode():
            return None

        if len(auth) == 1:
            msg = "不可用的JWT请求头!"
            raise exceptions.AuthenticationFailed(msg)
        elif len(auth) > 2:
            msg = '不可用的JWT请求头!JWT Token中间不应该有空格!'
            raise exceptions.AuthenticationFailed(msg)

        try:
            jwt_token = auth[1]
            jwt_info = jwt.decode(jwt_token,settings.SECRET_KEY)
            userid = jwt_info.get('userid')
            try:
                # 绑定当前user到request对象上
                user = User.objects.get(pk=userid)
                return user, jwt_token
            except:
                msg = '用户不存在!'
                raise exceptions.AuthenticationFailed(msg)
        except ExpiredSignatureError:
            msg = "JWT Token已过期!"
            raise exceptions.AuthenticationFailed(msg)

在视图中直接使用我们创建的这个方法

#view.py
rom rest_framework.views import APIView
from users.serializers import UserSerializer
from rest_framework.authtoken.serializers import AuthTokenSerializer
from django.contrib.auth import get_user_model

User = get_user_model()
from django.utils.timezone import now
from users.authentications import generate_jwt
from rest_framework.response import Response
from rest_framework_jwt.views import api_settings

class LoginView(APIView):
    def post(self, request):
        serializer = AuthTokenSerializer(data=request.data)
        if serializer.is_valid():
            user = serializer.validated_data.get('user')
            user.last_login = now()
            user.save()
            token = generate_jwt(user)
            user_serializer = UserSerializer(user)
            print(user)
            return Response({"token": token, "user":user_serializer.data})

        else:
            return Response({'message': "用户名或密码错误"})

最后urls.py中加上就行了

使用djangorestframework-jwt

安装

pip install djangorestframework-jwt

setting.py中配置相关

REST_FRAMEWORK = {
    # 'DEFAULT_PERMISSION_CLASSES': (
    #     'rest_framework.permissions.IsAuthenticated',
    # ),
    'DEFAULT_AUTHENTICATION_CLASSES': (
        'rest_framework_jwt.authentication.JSONWebTokenAuthentication',
        'rest_framework.authentication.SessionAuthentication',
        'rest_framework.authentication.BasicAuthentication',
    ),
}

在视图中我们直接使用手动生成令牌

from rest_framework.views import APIView
from users.serializers import UserSerializer
from rest_framework.authtoken.serializers import AuthTokenSerializer
from django.contrib.auth import get_user_model

User = get_user_model()
from django.utils.timezone import now
from users.authentications import generate_jwt
from rest_framework.response import Response
from rest_framework_jwt.views import api_settings
from rest_framework_jwt.authentication import JSONWebTokenAuthentication

class LoginView(APIView):
    def post(self, request):
        serializer = AuthTokenSerializer(data=request.data)
        if serializer.is_valid():
            user = serializer.validated_data.get('user')
            user.last_login = now()
            user.save()
            # token = generate_jwt(user)
            jwt_payload_handler = api_settings.JWT_PAYLOAD_HANDLER
            jwt_encode_handler = api_settings.JWT_ENCODE_HANDLER
            payload = jwt_payload_handler(user)
            token = jwt_encode_handler(payload)
            user_serializer = UserSerializer(user)
            print(user)
            return Response({"token": token, "user":user_serializer.data})

        else:
            return Response({'message': "用户名或密码错误"})

OK了 以后前端访问数据,直接携带token就行了

最后修改:2020年8月27日 17:26