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方法。

 

posted @ 2020-04-29 11:21  帅丶高高  阅读(676)  评论(0)    收藏  举报