前言 在前后端分离的开发模式下, 经常会用到Token进行验证鉴权, 今天我们来研究一下JWT。
安装 项目地址: django-rest-framework-simplejwt
本次使用的版本为 Django2.2 , Python 3.6.x
PIP安装 1 2 3 4 pip install django ==2.2 pip install djangorestframework ==3.10 pip install djangorestframework-simplejwt ==4.4.0 pip install PyJWT ==1.7.1
PS: 在尝试过程中,发现4.4.0版本与PyJWT有一个兼容性的bug, 在高版本中PyJWT返回的数据类型发生了变化, 导致djangorestframework-simplejwt后续代码报错,所以我们需要将版本指定为1.7.1。
具体问题请看: 326#issuecomment
配置 我们需要进行配置, 在 settings.py 中添加
1 2 3 4 5 6 7 8 9 10 REST_FRAMEWORK = { # Use Django's standard `django.contrib.auth` permissions, # or allow read-only access for unauthenticated users. 'DEFAULT_PERMISSION_CLASSES ': [ 'rest_framework.permissions.DjangoModelPermissionsOrAnonReadOnly ', ], 'DEFAULT_AUTHENTICATION_CLASSES ': ( 'rest_framework_simplejwt.authentication.JWTAuthentication ', ) }
在根urls.py文件中, 导入JWT已经写好的路由视图。
1 2 3 4 5 6 7 8 9 10 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' ), ]
如果还需要一个验证token的地址, 可以在导入一个写好的视图
1 2 3 4 5 urlpatterns = [ ... path('api/token/verify/' , TokenVerifyView.as_view(), name='token_verify' ), ... ]
使用JWT 创建serializers serializers.py
1 2 3 4 5 6 7 from django.contrib.auth.models import Userclass UserSerializer (serializers.HyperlinkedModelSerializer) : class Meta : model = User fields = ['url' , 'username' , 'email' , 'is_staff' ]
创建视图 views.py
1 2 3 4 5 6 7 8 9 10 from rest_framework import viewsets, permissionsfrom rest_framework_simplejwt import authenticationfrom django.contrib.auth.models import Userclass UserViewSet(viewsets.ModelViewSet): queryset = User.objects.all() serializer_class = UserSerializer permission_classes = [permissions.IsAuthenticated] authentication_classes = (authentication.JWTAuthentication,)
创建路由 在 urls.py 我们
1 2 3 4 5 6 7 8 9 10 11 12 13 14 from rest_framework import routersrouter = routers.DefaultRouter() router.register(r'users' , UserViewSet) urlpatterns = [ path('' , include(router.urls)), path('admin/' , admin.site.urls), path('api-auth/' , include('rest_framework.urls' )), path('api/token/' , TokenObtainPairView.as_view(), name='token_obtain_pair' ), path('api/token/refresh/' , TokenRefreshView.as_view(), name='token_refresh' ), path('api/token/verify/' , TokenVerifyView.as_view(), name='token_verify' ), ]
验证权限 此时我们访问http://127.0.0.1:8000/users/ 会出现
我们需要登录,或者提供Token才行
1 2 3 4 5 6 7 8 9 10 11 curl \ -X POST \ -H "Content-Type: application/json" \ -d '{"username" : "davidattenborough" , "password" : "boatymcboatface" }' \ http://localhost :8000 /api/token/ ... { "access" :"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX3BrIjoxLCJ0b2tlbl90eXBlIjoiYWNjZXNzIiwiY29sZF9zdHVmZiI6IuKYgyIsImV4cCI6MTIzNDU2LCJqdGkiOiJmZDJmOWQ1ZTFhN2M0MmU4OTQ5MzVlMzYyYmNhOGJjYSJ9.NHlztMGER7UADHZJlxNG0WSi22a2KaYSfd1S-AuT7lU" , "refresh" :"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX3BrIjoxLCJ0b2tlbl90eXBlIjoicmVmcmVzaCIsImNvbGRfc3R1ZmYiOiLimIMiLCJleHAiOjIzNDU2NywianRpIjoiZGUxMmY0ZTY3MDY4NDI3ODg5ZjE1YWMyNzcwZGEwNTEifQ.aEoAYkSJjoWH1boshQAaTkf8G3yn0kapko6HFRt7Rh4" }
1 2 3 curl \ -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX3BrIjoxLCJ0b2tlbl90eXBlIjoiYWNjZXNzIiwiY29sZF9zdHVmZiI6IuKYgyIsImV4cCI6MTIzNDU2LCJqdGkiOiJmZDJmOWQ1ZTFhN2M0MmU4OTQ5MzVlMzYyYmNhOGJjYSJ9.NHlztMGER7UADHZJlxNG0WSi22a2KaYSfd1S-AuT7lU" \ http://localhost:8000 /api/some -protected -view/
在类视图中使用Token 如果我们视图并不是数据接口,但是也需要token验证怎么办呢?
我们可以使用类视图进行验证
例如:views.py
1 2 3 4 5 6 7 8 9 10 11 12 from rest_framework.views import APIViewfrom rest_framework import permissionsfrom rest_framework_simplejwt import authenticationfrom django.http import HttpResponseclass Tcc (APIView) : permission_classes = [permissions.IsAuthenticated] authentication_classes = (authentication.JWTAuthentication,) def get (self, request, *args, **kwargs) : return HttpResponse('ok' )
urls.py
1 2 3 4 5 urlpatterns = [ ... path('aaa/' , views.Tcc .as_view ()), ... ]
在FBV中使用权限 此时我们需要引用装饰器
views.py
1 2 3 4 5 6 7 8 9 from rest_framework_simplejwt import authentication from rest_framework.decorators import api_view, permission_classes, authentication_classes @api_view(['GET' ]) @permission_classes([permissions.IsAuthenticated]) @authentication_classes((authentication.JWTAuthentication,) )def ttt(request): return HttpResponse('ok' )
urls.py
1 2 3 4 5 urlpatterns = [ ... path('ccc/' , views.ttt), ... ]
更改Token过期时间 token,默认过期时间是5分钟, 一些配置可以在settings.py中更改.
1 2 3 4 5 6 7 8 9 # Django project settings.py from datetime import timedelta... SIMPLE_JWT = { 'ACCESS_TOKEN_LIFETIME' : timedelta(minutes=30 ), }