DRF的版本认证权限

Posted yuncong

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了DRF的版本认证权限相关的知识,希望对你有一定的参考价值。

DRF的版本

版本控制是做什么用的, 我们为什么要用

首先我们要知道我们的版本是干嘛用的呢~~大家都知道我们开发项目是有多个版本的~~

当我们项目越来越更新~版本就越来越多~~我们不可能新的版本出了~以前旧的版本就不进行维护了~~~

那我们就需要对版本进行控制~~这个DRF也给我们提供了一些封装好的版本控制方法~~

版本控制怎么用

之前我们学视图的时候知道APIView,也知道APIView返回View中的view函数,然后调用的dispatch方法~

技术分享图片

执行self.initial方法之前是各种赋值,包括request的重新封装赋值,下面是路由的分发,那我们看下这个方法都做了什么~~

技术分享图片

我们可以看到,我们的version版本信息赋值给了 request.version  版本控制方案赋值给了 request.versioning_scheme~~

其实这个版本控制方案~就是我们配置的版本控制的类~~

也就是说,APIView通过这个方法初始化自己提供的组件~~

我们接下来看看框架提供了哪些版本的控制方法~~在rest_framework.versioning里~~

技术分享图片

详细用法

a. 基于url的get传参方式

如:/users?version=v1

技术分享图片 settings.py
技术分享图片 urls.py
技术分享图片
#!/usr/bin/env python
# -*- coding:utf-8 -*-
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework.versioning import QueryParameterVersioning


class TestView(APIView):
    versioning_class = QueryParameterVersioning

    def get(self, request, *args, **kwargs):

        # 获取版本
        print(request.version)
        # 获取版本管理的类
        print(request.versioning_scheme)

        # 反向生成URL
        reverse_url = request.versioning_scheme.reverse(test, request=request)
        print(reverse_url)

        return Response(GET请求,响应内容)

    def post(self, request, *args, **kwargs):
        return Response(POST请求,响应内容)

    def put(self, request, *args, **kwargs):
        return Response(PUT请求,响应内容)

views.py
views.py

b. 基于url的正则方式

如:/v1/users/

技术分享图片
REST_FRAMEWORK = {
    DEFAULT_VERSION: v1,            # 默认版本
    ALLOWED_VERSIONS: [v1, v2],   # 允许的版本
    VERSION_PARAM: version          # URL中获取值的key
}
settings.py
技术分享图片
from django.conf.urls import url, include
from web.views import TestView

urlpatterns = [
    url(r^(?P<version>[v1|v2]+)/test/, TestView.as_view(), name=test),
]

urls.py
urls.py
技术分享图片
#!/usr/bin/env python
# -*- coding:utf-8 -*-
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework.versioning import URLPathVersioning


class TestView(APIView):
    versioning_class = URLPathVersioning

    def get(self, request, *args, **kwargs):
        # 获取版本
        print(request.version)
        # 获取版本管理的类
        print(request.versioning_scheme)

        # 反向生成URL
        reverse_url = request.versioning_scheme.reverse(test, request=request)
        print(reverse_url)

        return Response(GET请求,响应内容)

    def post(self, request, *args, **kwargs):
        return Response(POST请求,响应内容)

    def put(self, request, *args, **kwargs):
        return Response(PUT请求,响应内容)

views.py
views.py

c. 基于 accept 请求头方式

如:Accept: application/json; version=1.0

技术分享图片
REST_FRAMEWORK = {
    DEFAULT_VERSION: v1,            # 默认版本
    ALLOWED_VERSIONS: [v1, v2],   # 允许的版本
    VERSION_PARAM: version          # URL中获取值的key
}
settings.py
技术分享图片
from django.conf.urls import url, include
from web.views import TestView

urlpatterns = [
    url(r^test/, TestView.as_view(), name=test),
]
urls.py
技术分享图片
#!/usr/bin/env python
# -*- coding:utf-8 -*-
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework.versioning import AcceptHeaderVersioning


class TestView(APIView):
    versioning_class = AcceptHeaderVersioning

    def get(self, request, *args, **kwargs):
        # 获取版本 HTTP_ACCEPT头
        print(request.version)
        # 获取版本管理的类
        print(request.versioning_scheme)
        # 反向生成URL
        reverse_url = request.versioning_scheme.reverse(test, request=request)
        print(reverse_url)

        return Response(GET请求,响应内容)

    def post(self, request, *args, **kwargs):
        return Response(POST请求,响应内容)

    def put(self, request, *args, **kwargs):
        return Response(PUT请求,响应内容)
views.py

d. 基于主机名方法

如:v1.example.com

技术分享图片
ALLOWED_HOSTS = [*]
REST_FRAMEWORK = {
    DEFAULT_VERSION: v1,  # 默认版本
    ALLOWED_VERSIONS: [v1, v2],  # 允许的版本
    VERSION_PARAM: version  # URL中获取值的key
}
settings.py
技术分享图片
from django.conf.urls import url, include
from web.views import TestView

urlpatterns = [
    url(r^test/, TestView.as_view(), name=test),
]
urls.py
技术分享图片
#!/usr/bin/env python
# -*- coding:utf-8 -*-
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework.versioning import HostNameVersioning


class TestView(APIView):
    versioning_class = HostNameVersioning

    def get(self, request, *args, **kwargs):
        # 获取版本
        print(request.version)
        # 获取版本管理的类
        print(request.versioning_scheme)
        # 反向生成URL
        reverse_url = request.versioning_scheme.reverse(test, request=request)
        print(reverse_url)

        return Response(GET请求,响应内容)

    def post(self, request, *args, **kwargs):
        return Response(POST请求,响应内容)

    def put(self, request, *args, **kwargs):
        return Response(PUT请求,响应内容)
views.py

e. 基于django路由系统的namespace

如:example.com/v1/users/

技术分享图片
REST_FRAMEWORK = {
    DEFAULT_VERSION: v1,  # 默认版本
    ALLOWED_VERSIONS: [v1, v2],  # 允许的版本
    VERSION_PARAM: version  # URL中获取值的key
}
settings.py
技术分享图片
from django.conf.urls import url, include
from web.views import TestView

urlpatterns = [
    url(r^v1/, ([
                      url(rtest/, TestView.as_view(), name=test),
                  ], None, v1)),
    url(r^v2/, ([
                      url(rtest/, TestView.as_view(), name=test),
                  ], None, v2)),

]
urls.py
技术分享图片
#!/usr/bin/env python
# -*- coding:utf-8 -*-
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework.versioning import NamespaceVersioning


class TestView(APIView):
    versioning_class = NamespaceVersioning

    def get(self, request, *args, **kwargs):
        # 获取版本
        print(request.version)
        # 获取版本管理的类
        print(request.versioning_scheme)
        # 反向生成URL
        reverse_url = request.versioning_scheme.reverse(test, request=request)
        print(reverse_url)

        return Response(GET请求,响应内容)

    def post(self, request, *args, **kwargs):
        return Response(POST请求,响应内容)

    def put(self, request, *args, **kwargs):
        return Response(PUT请求,响应内容)
views.py

f. 全局使用

技术分享图片
REST_FRAMEWORK = {
    DEFAULT_VERSIONING_CLASS:"rest_framework.versioning.URLPathVersioning",
    DEFAULT_VERSION: v1,
    ALLOWED_VERSIONS: [v1, v2],
    VERSION_PARAM: version 
}
settings.py

DRF的认证

上面讲版本的时候我们知道~在dispatch方法里~执行了initial方法~~那里初始化了我们的版本~~

如果我们细心我们能看到~版本的下面其实就是我们的认证,权限,频率组件了~~

我们先看看我们的认证组件~~

技术分享图片

我们进去我们的认证看下~~

技术分享图片

我们这个权限组件返回的是request.user,那我们这里的request是新的还是旧的呢~~

我们的initial是在我们request重新赋值之后的~所以这里的request是新的~也就是Request类实例对象~~

那这个user一定是一个静态方法~我们进去看看~~

技术分享图片

技术分享图片

技术分享图片

 

 

 

技术分享图片

很明显,有传参

技术分享图片

技术分享图片

 

我们通过上面基本可以知道我们的认证类一定要实现的方法~~以及返回值类型~~以及配置的参数authentication_classes~

DRF的权限 

权限是什么

大家之前都应该听过权限~那么我们权限到底是做什么用的呢~~

大家都有博客~或者去一些论坛~一定知道管理员这个角色~

比如我们申请博客的时候~一定要向管理员申请~也就是说管理员会有一些特殊的权利~是我们没有的~~

这些对某件事情决策的范围和程度~我们叫做权限~~权限是我们在项目开发中非常常用到的~~

那我们看DRF框架给我们提供的权限组件都有哪些方法~~

权限组件源码

我们之前说过了DRF的版本和认证~也知道了权限和频率跟版本认证都是在initial方法里初始化的~~

技术分享图片

技术分享图片

其实我们版本,认证,权限,频率控制走的源码流程大致相同~~大家也可以在源码里看到~~

我们的权限类一定要有has_permission方法~否则就会抛出异常~~这也是框架给我提供的钩子~~

我们先看到在rest_framework.permissions这个文件中~存放了框架给我们提供的所有权限的方法~~

技术分享图片

我这里就不带着大家详细去看每一个了~大家可以去浏览一下每个权限类~看看每个都是干嘛的~~

这里主要说下BasePermission 这个是我们写权限类继承的一个基础权限类~~~ 

认证权限的详细用法

 用户url传入的token认证

技术分享图片
from django.db import models

# Create your models here.


class User(models.Model):
    name = models.CharField(max_length=32)
    pwd = models.CharField(max_length=32)
    token = models.UUIDField(null=True, blank=True)#随机字符串
    CHOICES = ((1, "vip"), (2, "普通用户"), (3, "vvip"))
    type = models.IntegerField(choices=CHOICES, default=2)
DRFDemo/AuthDemo/models.py

执行:makemigrations AuthDemo
migrate AuthDemo

技术分享图片
from django.conf.urls import url, include
from django.contrib import admin



urlpatterns = [
    url(r^admin/, admin.site.urls),
    url(r^book/, include("SerDemo.urls")),
    url(r^api/user/, include("AuthDemo.urls")),
    url(r^api/(?P<version>[v1|v2]+)/, include("VersionDemo.urls")),
]        
DRFDemo/DRFDemo/urls.py
技术分享图片
from django.conf.urls import url, include
from django.contrib import admin
from .views import RegisterView, LoginView, TestView, PermissionView

urlpatterns = [
    url(r^register, RegisterView.as_view()),
    url(r^login, LoginView.as_view()),
    url(r^test, TestView.as_view()),
    url(r^permission, PermissionView.as_view()),

]        
DRFDemo/AuthDemo/urls.py
技术分享图片
from django.shortcuts import render
from rest_framework.views import APIView
from rest_framework.response import Response
from .models import User
import uuid
from utils.auth import MyAuth
from utils.permission import MyPermission

# Create your views here.


class RegisterView(APIView):
    def post(self, request):
        name = request.data.get("name", "")
        pwd = request.data.get("pwd", "")
        if name and pwd:
            User.objects.create(name=name, pwd=pwd)
            return Response("注册成功")
        return Response("用户名或密码不合法")        
        
class LoginView(APIView):
    def post(self, request):
        name = request.data.get("name", "")
        pwd = request.data.get("pwd", "")
        user_obj = User.objects.filter(name=name, pwd=pwd).first()
        if user_obj:
            # 登录成功 创建一个token并给前端返回
            token = uuid.uuid4()
            user_obj.token = token
            user_obj.save()
            return Response(token)
        return Response("用户名或密码错误")        

class TestView(APIView):
    authentication_classes = [MyAuth, ]

    def get(self, request):
        print(request.user)
        print(request.user.name)
        print(request.auth)
        return Response("登录后发送的数据")


class PermissionView(APIView):
    authentication_classes = [MyAuth, ]
    permission_classes = [MyPermission, ]

    def get(self, request):
        # 这个接口只能vip或者vvip访问
        return Response("权限测试接口")        
DRFDemo/AuthDemo/views.py
技术分享图片
REST_FRAMEWORK = {
    # "DEFAULT_VERSIONING_CLASS": "utils.version.MyVersion",
    "DEFAULT_VERSIONING_CLASS": "rest_framework.versioning.URLPathVersioning",
    DEFAULT_VERSION: "v1",
    ALLOWED_VERSIONS: ["v1", "v2"],
    VERSION_PARAM: version,
    # 配置认证类
    # "DEFAULT_AUTHENTICATION_CLASSES": ["utils.auth.MyAuth", ]
}
DRFDemo/DRFDemo/settings.py
技术分享图片
from rest_framework import permissions


class MyPermission(permissions.BasePermission):
    message = "请充VIP,999一年"

    def has_permission(self, request, view):
        # 判断用户是否有权限
        if request.user.type in [1, 3]:
            return True
        return False        
        
DRFDemo/utils/permission.py

以上是关于DRF的版本认证权限的主要内容,如果未能解决你的问题,请参考以下文章

DRF 版本认证权限限制解析器和渲染器

DRF 版本认证权限限制解析器和渲染器

DRF的版本认证权限

DRF的版本认证权限

drf认证节流权限版本

DRF之版本控制认证和权限组件