1. 程式人生 > >DRF的版本、認證、權限

DRF的版本、認證、權限

字符串 hide head render ren model fde ger 方式

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

技術分享圖片
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 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的版本、認證、權限