Django笔记(七):JWT认证

前后端分离的项目更多使用JWT认证------Json Web Token。本文记录djangorestframework-simplejwt的使用方式。文档

安装

pip install djangorestframework-simplejwt

配置settings.py:

python 复制代码
INSTALLED_APPS = [
    'rest_framework_simplejwt',
]

REST_FRAMEWORK = {
    'DEFAULT_AUTHENTICATION_CLASSES': (
        'rest_framework_simplejwt.authentication.JWTAuthentication',
    )
}

from datetime import timedelta

SIMPLE_JWT = {
    "ACCESS_TOKEN_LIFETIME": timedelta(minutes=5), # access有效时间
    "REFRESH_TOKEN_LIFETIME": timedelta(days=1), # refresh有效时间
    "ROTATE_REFRESH_TOKENS": False,
    "BLACKLIST_AFTER_ROTATION": False,
    "UPDATE_LAST_LOGIN": False,

    "ALGORITHM": "HS256",
    "SIGNING_KEY": "WoShiLuanXieDe123456", # 加密秘钥
    "VERIFYING_KEY": "",
    "AUDIENCE": None,
    "ISSUER": None,
    "JSON_ENCODER": None,
    "JWK_URL": None,
    "LEEWAY": 0,

    "AUTH_HEADER_TYPES": ("Bearer",), # 请求头用来标记token的字符串
    "AUTH_HEADER_NAME": "HTTP_AUTHORIZATION",
    "USER_ID_FIELD": "id",
    "USER_ID_CLAIM": "user_id",
    "USER_AUTHENTICATION_RULE": "rest_framework_simplejwt.authentication.default_user_authentication_rule",

    "AUTH_TOKEN_CLASSES": ("rest_framework_simplejwt.tokens.AccessToken",),
    "TOKEN_TYPE_CLAIM": "token_type",
    "TOKEN_USER_CLASS": "rest_framework_simplejwt.models.TokenUser",

    "JTI_CLAIM": "jti",

    "SLIDING_TOKEN_REFRESH_EXP_CLAIM": "refresh_exp",
    "SLIDING_TOKEN_LIFETIME": timedelta(minutes=5),
    "SLIDING_TOKEN_REFRESH_LIFETIME": timedelta(days=1),

    "TOKEN_OBTAIN_SERIALIZER": "rest_framework_simplejwt.serializers.TokenObtainPairSerializer",
    "TOKEN_REFRESH_SERIALIZER": "rest_framework_simplejwt.serializers.TokenRefreshSerializer",
    "TOKEN_VERIFY_SERIALIZER": "rest_framework_simplejwt.serializers.TokenVerifySerializer",
    "TOKEN_BLACKLIST_SERIALIZER": "rest_framework_simplejwt.serializers.TokenBlacklistSerializer",
    "SLIDING_TOKEN_OBTAIN_SERIALIZER": "rest_framework_simplejwt.serializers.TokenObtainSlidingSerializer",
    "SLIDING_TOKEN_REFRESH_SERIALIZER": "rest_framework_simplejwt.serializers.TokenRefreshSlidingSerializer",
}

上述代码中注释部分可自定义,秘钥随便写越复杂越好,不要泄露。

simplejwt包含一个access和一个refresh,一个前端请求想通过后端验证,头部需要包含access,如果access过期且refresh没有过期,则可以通过refresh刷新access。

视图

python 复制代码
from rest_framework_simplejwt.views import (
    TokenObtainPairView,
    TokenRefreshView,
)

urlpatterns = [
    ...
    path('api/token/', TokenObtainPairView.as_view(), name='token_obtain_pair'),
    path('api/token/refresh/', TokenRefreshView.as_view(), name='token_refresh'),
    ...
]

simplejwt写好了两个视图,TokenObtainPairView用来获取access和refresh,TokenRefreshView用来刷新access。

TokenObtainPairView

如图,此视图需要POST方法提交用户名和密码(Django的user模型)。提交后:

返回一个refresh和access:

python 复制代码
{
    "refresh": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ0b2tlbl90eXBlIjoicmVmcmVzaCIsImV4cCI6MTcwNjI1NzA2MiwianRpIjoiNWRiMTRhNWQyZDhkNDBiZWE0N2I4ZjdiNDJlMDk3ZGUiLCJ1c2VyX2lkIjoxfQ.4kc2U33GNTAJVUUBurJWUta8LNbNlB0Ec85H5ZqCsTg",
    "access": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ0b2tlbl90eXBlIjoiYWNjZXNzIiwiZXhwIjoxNzA2MTcwOTYyLCJqdGkiOiJjZDg2MDhhNzVlZGY0ZjBlODZiMmVjMWYyZjg2NmFkMCIsInVzZXJfaWQiOjF9.00fjHdR2BcQrcvk6mciof2JdacaXOOx6ba-eaS5wf_w"
}

(如果报str类型无decode的错误,是因为版本问题,可以定位到源码部分将token.decode()改成token)

TokenRefreshView

此视图POST一个refresh,返回一个新的access,将刚生成的refresh提交:

得到一个新的access:

python 复制代码
{
    "access": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ0b2tlbl90eXBlIjoiYWNjZXNzIiwiZXhwIjoxNzA2MTcxMjA2LCJqdGkiOiIzOWE4N2YyOGM5ZjQ0ZDE2YmM0ZWU2NmQ4NmM1ZDc3YyIsInVzZXJfaWQiOjF9.qHZzS8xP0x0jGD5vncHEtFaXYRNEjo8NeTwFEAn9FCM"
}

解析JWT

jwt只是一种编码方式,可以直接将上述内容在线解析,Python解析JWT可以通过这种方式:

python 复制代码
from base64 import urlsafe_b64decode
from json import loads

def jwt_decode(access):
    base64_str = access.split('.')[1]
    size = len(base64_str) % 4
    if size == 2:
        base64_str += '=='
    elif size == 3:
        base64_str += '='
    elif size != 0:
        raise ValueError('Invalid base64 string')
    payload = urlsafe_b64decode(base64_str.encode('utf-8')).decode()
    return loads(payload)

前端解析可以靠jwt-decode库。

使用JWT认证

在需要使用JWT认证的试图类中加上:

python 复制代码
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework.permissions import IsAuthenticated

class IndexView(APIView):
    permission_classes = ([IsAuthenticated])
    def get(self, request):
        players = Player.objects.all()
        return Response(PlayersModelSerializer(players, many=True).data)

这样再访问index试图时,会提示未提供验证:

需要在请求中添加头信息Authorization:

python 复制代码
headers: {
            'Authorization': 'Bearer ' + token.access,
        },

这里的Bearer是配置文件中SIMPLE_JWT的AUTH_HEADER_TYPES项,可自定义,但一定要和配置对应。在"Bearer"标识和access之间需要隔开一个空格,即"Bearer "+access,而不是"Bearer"+access。

使用postman测试下,添加头信息:

成功返回结果。postman可以直接添加Authorization,如果提供的是过期的access会返回:

前端根据发送请求使用的工具不同,对应添加头部信息即可,如ajax:

javascript 复制代码
$.ajax({
        url: 'https://yuming/api/index/',
        type: 'GET',
        headers: {
            'Authorization': 'Bearer ' + token.access,
        },
        data: {

        },
        async : false,
        success(resp){
            console.log(resp);
        }
    });
相关推荐
从以前23 分钟前
【算法题解】Bindian 山丘信号问题(E. Bindian Signaling)
开发语言·python·算法
海绵波波10735 分钟前
flask后端开发(9):ORM模型外键+迁移ORM模型
后端·python·flask
余生H40 分钟前
前端Python应用指南(二)深入Flask:理解Flask的应用结构与模块化设计
前端·后端·python·flask·全栈
CriticalThinking1 小时前
Pycharm不正常识别包含中文路径的解释器
ide·python·pycharm
m0_689618281 小时前
数学建模助力干细胞研究,配体纳米簇如何影响干细胞命运
笔记·数学建模
sin22012 小时前
springboot数据校验报错
spring boot·后端·python
eric-sjq2 小时前
基于xiaothink对Wanyv-50M模型进行c-eval评估
人工智能·python·语言模型·自然语言处理·github
是十一月末2 小时前
机器学习之KNN算法预测数据和数据可视化
人工智能·python·算法·机器学习·信息可视化
工业互联网专业2 小时前
基于OpenCV和Python的人脸识别系统_django
人工智能·python·opencv·django·毕业设计·源码·课程设计