6-7 认证和权限-DRF认证之jwt认证
目录:
- JWT认证 介绍
- JWT 认证环境准备
- JWT 认证基本使用
- JWT 认证权限
一、JWT 认证介绍
使用django rest framework 开发api并使用 json web token(JWT)进行身份验证,使用django-rest-framework-jwt这个库来帮助我们简单的使用jwt进行身份验证。
那我们用JWT认证有哪些优点和缺点呐?
优点:
- 无状态:JWT的token不会存在 服务器中,它是存在客户端上的,这样我们就更好管理。
- 避免csrf:意思就是 已经帮你封装好了,不需要在进行 csrf 验证。
- 比较适合给移动端 提供 api
缺点:
- 注销登录后Token时效问题:因为token存在客户端上,所以就导致 有时候,比如说我们修改密码,然后注销用户导致token还在有效期内,token还能继续使用。那么就没有办法控制它。我们可以通过 redis缓存来解决这个问题。
二、JWT 认证环境准备
2.1、安装
pip install djangorestframework-jwt
2.2、注册
说明:在settings.py文件中的INSTALLED_APPS中注册 rest_framework.authtoken
INSTALLED_APPS = [
''''''
'rest_framework',
'rest_framework.authtoken', #注册
]
2.3、配置
说明:我们在settings.py中配置jwt认证,已经过期时间。当然这个是全局的。
# 全局配置 JWT 验证
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': (
'rest_framework_jwt.authentication.JSONWebTokenAuthentication', # 配置验证方式为Token验证
),
'DEFAULT_PERMISSION_CLASSES': (
'rest_framework.permissions.IsAuthenticated', #配置全局权限
)
}
#配置JWT的token的超时时间
JWT_AUTH = {
'JWT_EXPIRATION_DELTA': datetime.timedelta(days=7), # Token 过期时间为一周
'JWT_AUTH_HEADER_PREFIX': 'JWT', # Token的头为:JWT adashkjdhaskjhd21312312
'JWT_ALLOW_REFRESH': False, #True允许刷新,False不允许刷新
}
2.4、路由
说明:其实JWT认证跟token认证一样,都需要在 路由下配置 1个函数路由,生成 token值。
#根级路由
from django.contrib import admin
from django.urls import path, include
from rest_framework_jwt.views import obtain_jwt_token #导入生成路由函数
urlpatterns = [
path('admin/', admin.site.urls),
path('api/', include('app05.urls')),
path('api-token-auth/', obtain_jwt_token) #配置生成token路由
]
好咧!配置好了,我们来用 postman测试一下,看看能否生成一个 token值:

三、JWT 认证基本使用
3.1、增加返回信息
说明:我们的返回信息只有 token值,不能满足我们的需求,我们通过修改该视图的返回值可以完成我们的需求,比如说:我们在返回token的同时,我们还想返回 userid和username。以及其他信息呐。所以在我们的应用中(app05)新建一个 utils.py 文件。
目录结构:
-app05(应用)
-migrations
...
-models.py
-admin.py
-permissions.py
-utils.py #新建utils.py,存放工具类或者工具函数
....
好啦,那我们就编辑 utils.py 文件,新增 jwt_response_payload_handler 函数:
def jwt_response_payload_handler(token, user=None, request=None):
return {
'token': token,
'id': user.id,
'username': user.username, #这边缺的话,还可以加。哈哈,满足我们的需求啦
}
后面还需要在settings.py文件中的 JWT_AUTH 中导入 jwt_response_payload_handler:
#settings.py配置中加
JWT_AUTH = {
'JWT_EXPIRATION_DELTA': datetime.timedelta(days=7), # Token 过期时间为一周
'JWT_ALLOW_REFRESH': False,
'JWT_AUTH_HEADER_PREFIX': 'JWT',
'JWT_RESPONSE_PAYLOAD_HANDLER': 'app05.utils.jwt_response_payload_handler', #导入我们刚刚定义的jwt_response_payload_handler,告诉这个工具类,你要给我返回我想要的数据。
}
我们再来用postman测试一下:

3.2、JWT认证
说明:我们这边还是用局部认证,如果想用全局认证,就是说对所有的都有效的话,那么在 settings.py配置即可(在2.3配置中有)。
from rest_framework.views import APIView
from django.http import JsonResponse
from rest_framework.permissions import IsAuthenticated
from rest_framework_jwt.authentication import JSONWebTokenAuthentication #配置局部的,只需导入即可
class CartView(APIView):
# 基于什么登录认证的
authentication_classes = [JSONWebTokenAuthentication] #基于 JWT认证
# 只有登录才能访问
permission_classes = [IsAuthenticated] #需要登录权限
def get(self, request, *args, **kwargs):
ctx = {
"code": 1,
"msg": "ok",
"data": {
"goods": [
{
"name": "苹果",
"price": 12
}
]
}
}
return JsonResponse(ctx)
那我们来看看 JSONWebTokenAuthentication 的继承谁呐?来 老规矩:
Ctrl +JSONWebTokenAuthentication -> BaseJSONWebTokenAuthentication -> BaseAuthentication
我去还是继承的是 BaseAuthentication 基础的认证方式,跟 basic、session、token是一样的。
ok,那我们拿到上面生产的token值,用postman测试一下:入参方式(headers):Authorization:JWT token值

3.3、局部不配置权限
说明:上面只是拿了局部来测试的。那有同学说了,我全局配置了 JWT 用户认证,但是我在 某个视图中不想配置 登录权限,对吧,我不想 通过登录的方式 获取 token,然后再去获取到我的 JSON 格式的数据。那咋办呐?我只需要把 局部的视图 的权限置为空就行了。
class CartView(APIView):
# 基于什么登录认证的
#authentication_classes = [JSONWebTokenAuthentication] #需要注释掉
# 只有登录才能访问
permission_classes = [] #全局配置之后,这边直接置空,就不需要登录认证了
def get(self, request, *args, **kwargs):
....
return JsonResponse(ctx)
测试一下:

哈哈,果然有用。
四、JWT 认证权限
我们之前学过 drf的权限管理(6-2 认证和权限-DRF权限),就是说什么呐,你创建的用户,其他的认证用户只能看,或者只有读取权限,没有创建的权限,只有你自己才有创建,修改、删除等权限。那 JWT 这边是怎么做的呐?我们来看看。其实我们之前那么做的方式也可以实现这种方式,两种方式你任选一种。
4.1、权限设置
说明:同样我们要在 新建的 permissions.py 文件编写我们的权限代码。
from rest_framework_jwt.authentication import jwt_decode_handler
from rest_framework import permissions
class IsOwnerOrReadOnly(permissions.BasePermission):
def has_object_permission(self, request, view, obj):
if request.method in permissions.SAFE_METHODS: #get方法直接返回true
return True
token = request.META.get('HTTP_AUTHORIZATION')[5:] #先把token值取出来,[5:]表示从JWT+两个空格后面的值是token值
token_user = jwt_decode_handler(token) #解析token值,解析出来是一个user对象
if token_user:
#证明 当前jwt验证的用户就是数据创建者
return obj.user.id == token_user.get('user_id') #token_user是一个dict类型,字典中包含user_id
return False
4.2、视图
说明:我们权限设置好了,需要在视图中加权限认证
....
from rest_framework_jwt.authentication import JSONWebTokenAuthentication
from .permissions import IsOwnerOrReadOnly #导入自定义权限认证
class CartView(APIView):
# 基于什么登录认证的
authentication_classes = [JSONWebTokenAuthentication]
# 只有登录才能访问
permission_classes = [IsAuthenticated, IsOwnerOrReadOnly] #加到这边就行了,但是一定要加认证类(IsAuthenticated),如果认证类是全局的话,就加IsOwnerOrReadOnly就可以了
def get(self, request, *args, **kwargs):
....
return JsonResponse(ctx)
这边就不测试了,因为我们这边没有做post方法,或者 patch方法。

浙公网安备 33010602011771号