Django笔记(七):JWT认证

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

安装

pip install djangorestframework-simplejwt

配置settings.py:

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。

视图

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:

{
    "refresh": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ0b2tlbl90eXBlIjoicmVmcmVzaCIsImV4cCI6MTcwNjI1NzA2MiwianRpIjoiNWRiMTRhNWQyZDhkNDBiZWE0N2I4ZjdiNDJlMDk3ZGUiLCJ1c2VyX2lkIjoxfQ.4kc2U33GNTAJVUUBurJWUta8LNbNlB0Ec85H5ZqCsTg",
    "access": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ0b2tlbl90eXBlIjoiYWNjZXNzIiwiZXhwIjoxNzA2MTcwOTYyLCJqdGkiOiJjZDg2MDhhNzVlZGY0ZjBlODZiMmVjMWYyZjg2NmFkMCIsInVzZXJfaWQiOjF9.00fjHdR2BcQrcvk6mciof2JdacaXOOx6ba-eaS5wf_w"
}

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

TokenRefreshView

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

得到一个新的access:

{
    "access": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ0b2tlbl90eXBlIjoiYWNjZXNzIiwiZXhwIjoxNzA2MTcxMjA2LCJqdGkiOiIzOWE4N2YyOGM5ZjQ0ZDE2YmM0ZWU2NmQ4NmM1ZDc3YyIsInVzZXJfaWQiOjF9.qHZzS8xP0x0jGD5vncHEtFaXYRNEjo8NeTwFEAn9FCM"
}

 解析JWT

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

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认证的试图类中加上:

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:

headers: {
            'Authorization': 'Bearer ' + token.access,
        },

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

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

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

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

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

        },
        async : false,
        success(resp){
            console.log(resp);
        }
    });

相关推荐

  1. JWT 认证机制

    2024-01-29 09:06:02       29 阅读
  2. 分布式认证JWT

    2024-01-29 09:06:02       26 阅读
  3. 安全认证机制之JWT

    2024-01-29 09:06:02       33 阅读

最近更新

  1. TCP协议是安全的吗?

    2024-01-29 09:06:02       16 阅读
  2. 阿里云服务器执行yum,一直下载docker-ce-stable失败

    2024-01-29 09:06:02       16 阅读
  3. 【Python教程】压缩PDF文件大小

    2024-01-29 09:06:02       15 阅读
  4. 通过文章id递归查询所有评论(xml)

    2024-01-29 09:06:02       18 阅读

热门阅读

  1. 网路服务器——线程池技术

    2024-01-29 09:06:02       31 阅读
  2. 小世界网络 | 小世界网络(Python)

    2024-01-29 09:06:02       36 阅读
  3. myql入门

    2024-01-29 09:06:02       31 阅读
  4. Redis面试题35

    2024-01-29 09:06:02       31 阅读
  5. Vue路由

    2024-01-29 09:06:02       33 阅读
  6. 【洛谷题解】P1706 全排列问题

    2024-01-29 09:06:02       38 阅读
  7. Redis 事务

    2024-01-29 09:06:02       34 阅读
  8. MyBatis框架-XML映射器

    2024-01-29 09:06:02       24 阅读
  9. 关键点标注工具

    2024-01-29 09:06:02       28 阅读