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);
        }
    });
相关推荐
DeviceHub3 小时前
硬件工程师选型笔记:ALPS RK12L1230C0K 与 Tonevee RK12L1230C0K 电位器 PIN TO PIN 评估指南
笔记
互联网中的一颗神经元3 小时前
小白python入门 - 39. 采集流水线小项目
开发语言·python
whyTeaFo3 小时前
GAMES101: Lecture 13: Ray Tracing 1 (Whitted-Style Ray Tracing) ppt笔记
笔记
郭老二4 小时前
【Python】常用模块:xmlrpc
python
名字还没想好☜4 小时前
Python itertools 实战:用 groupby、chain、islice 优雅处理大数据流
linux·windows·python·迭代器·itertools
威联通网络存储5 小时前
TS-h2490FU在面板制造Array段AOI缺陷画廊中的并联
python·制造
接针5 小时前
UV 常用命令
python·uv
无垠的广袤7 小时前
【工业树莓派 CM0 Dev Board】扩展板设计
linux·python·嵌入式硬件·pcb设计·模块化·传感器
Yolanda_20228 小时前
在vscode终端中可使用pip,但是cmd终端中找不到命令 pip问题的解决
vscode·python·conda·pip
2301_764441338 小时前
用动力学系统(微分方程)为 Kernberg 的客体关系单元提供数学化的操作定义,把“自体—客体“这对心理结构建模成一个二维耦合系统
数据结构·python·算法·数学建模