momo's Blog.

Django drf前后端分离中JWT认证

字数统计: 663阅读时长: 3 min
2021/05/19 Share

前言

在前后端分离的开发模式下, 经常会用到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 User


class 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, permissions
from rest_framework_simplejwt import authentication
from django.contrib.auth.models import User

class 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 routers

router = 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"
}

  • 使用token登录
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 APIView
from rest_framework import permissions
from rest_framework_simplejwt import authentication
from django.http import HttpResponse


class 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),
}
CATALOG
  1. 1. 前言
  2. 2. 安装
    1. 2.1. PIP安装
  3. 3. 配置
  4. 4. 使用JWT
    1. 4.1. 创建serializers
    2. 4.2. 创建视图
    3. 4.3. 创建路由
  5. 5. 验证权限
  6. 6. 在类视图中使用Token
  7. 7. 在FBV中使用权限
  8. 8. 更改Token过期时间