DRF認(rèn)證,權(quán)限,節(jié)流,版本,解析器的基本使用

認(rèn)證&權(quán)限
認(rèn)證和權(quán)限是一起用的。
可以再配置文件中settings配置全局默認(rèn)的認(rèn)證&權(quán)限

REST_FRAMEWORK = {
    # python中認(rèn)證的配置
    'DEFAULT_AUTHENTICATION_CLASSES': (
        'rest_framework.authentication.BasicAuthentication',   # 基本認(rèn)證
        'rest_framework.authentication.SessionAuthentication',  # session認(rèn)證
    )
    # python中權(quán)限的配置,如果沒(méi)有指明,系統(tǒng)默認(rèn)的權(quán)限是允許所有人訪問(wèn)的
    'DEFAULT_PERMISSION_CLASSES': (
        'rest_framework.permissions.AllowAny',
    )
}

也可以在每個(gè)視圖中通過(guò)設(shè)置authentication_classess屬性來(lái)設(shè)置

從DRF框架中導(dǎo)入包authentication

from rest_framework.authentication import SessionAuthentication, BasicAuthentication
from rest_framework.views import APIView
class ExampleView(APIView):
    # 在子應(yīng)用中定義authentication_classes,可以寫(xiě)一個(gè)也可以寫(xiě)多個(gè)
    # authentication_classes = (SessionAuthentication, BasicAuthentication)
    # 配合權(quán)限來(lái)使用我們寫(xiě)一個(gè)。
    authentication_classes = [SessionAuthentication]

提供的權(quán)限

1.AllowAny 允許所有用戶
2.IsAuthenticated 僅通過(guò)認(rèn)證的用戶
3.IsAdminUser 僅管理員用戶
4.IsAuthenticatedOrReadOnly 認(rèn)證的用戶可以完全操作,否則只能get讀取

自定義權(quán)限

如需自定義權(quán)限,需繼承rest_framework.permissions.BasePermission父類(lèi),并實(shí)現(xiàn)以下兩個(gè)任何一個(gè)方法或全部

.has_permission(self, request, view)

是否可以訪問(wèn)視圖, view表示當(dāng)前視圖對(duì)象,如果沒(méi)有設(shè)置的話默認(rèn)的是True,如果設(shè)置
False則表示所有的用戶都不能訪問(wèn)該視圖

.has_object_permission(self, request, view, obj)

是否可以訪問(wèn)數(shù)據(jù)對(duì)象, view表示當(dāng)前視圖, obj為數(shù)據(jù)對(duì)象,控制視圖能夠訪問(wèn)添加了權(quán)限控制類(lèi)的數(shù)據(jù)對(duì)象

class MyPermission(BasePermission):
    def has_permission(self, request, view)
        """讓所有用戶都有權(quán)限"""
        return True
    def has_object_permission(self, request, view, obj):
        """用戶是否有權(quán)限訪問(wèn)添加了權(quán)限控制類(lèi)的數(shù)據(jù)對(duì)象"""
        # 需求:用戶能夠訪問(wèn)id為1,3的對(duì)象,其他的不能夠訪問(wèn)
        if obj.id in (1, 3):
            return True
        else:
            return False

class BookInfoViewSet(ModelViewSet):
    queryset = BookInfo.objects.all()
    serializer_class = BookInfoSerializer
    # 表示登錄有權(quán)限
    permission_classes = [IsAuthenticated]
    # 表示所有用戶都有權(quán)限,只能夠訪問(wèn)id 為1,3的數(shù)據(jù)
    permission_classes = [MyPermission]
   

節(jié)流

源碼流程

和認(rèn)證的流程一樣,進(jìn)入initial(request)
其中check_throttles(request)是節(jié)流的函數(shù)
VisitThrottle自定義權(quán)限類(lèi)
allow_request()返回值:
True, 允許訪問(wèn)
False, 訪問(wèn)太頻繁
wait()返回值:
返回一個(gè)整數(shù),表示下次還有多久可以訪問(wèn)
使用自定義類(lèi)

class VisitThrottle(BaseThrottle):
    def __init__(self):
        self.history = []

    def allow_request(self, request, view):
        remote_addr = request.META.get('REMOTE_ADDR')
        ctime = time.time()
        if remote_addr not in VISIT_RECORD:
            print("沒(méi)有此IP")
            VISIT_RECORD[remote_addr] = [ctime, ]
            return True

        history = VISIT_RECORD.get(remote_addr)

        print(history)

        while history and history[-1] < ctime-8:
            history.pop()

        self.history = history
        if len(history) < 3:
            history.insert(0, ctime)
            return True

    def wait(self):

        ctime = time.time()
        return 8-(ctime-self.history[-1])

在定義的類(lèi)中復(fù)寫(xiě)allow_request方法,返回True或者False表示可以訪問(wèn)或者訪問(wèn)頻率太高
引入

settings.py

DEFAULT_THROTTLE_CLASSES': ['apps.api.utils.throttle.UserThrottle'],


#2.局部

class AuthView(APIView): 
    用于用戶登錄認(rèn)證
    throttle_classes = [VisitThrottle,]
自定義類(lèi)繼承內(nèi)置類(lèi)
# throttle.py
from rest_framework.throttling import  SimpleRateThrottle
class VisitThrottle(SimpleRateThrottle):
    scope = "Vistor"

    def get_cache_key(self, request, view):
        return self.get_ident(request)

class UserThrottle(SimpleRateThrottle):
    scope = "User"

    def get_cache_key(self, request, view):
        return self.user.username
scope從settings.py中尋找DEFAULT_THROTTLE_RATES字典的Key,就是訪問(wèn)頻率限制,scope可以區(qū)分不同的函數(shù)的不同限制;get_cache_key(self, request, view)返回一個(gè)唯一標(biāo)示用以區(qū)分不同的用戶,對(duì)于匿名用戶返回IP保存到緩存中限制訪問(wèn),對(duì)于注冊(cè)的用戶取用戶名(唯一)來(lái)區(qū)分就可以。

settings.py

'DEFAULT_THROTTLE_RATES': {
  'Vistor': '3/m',
  'User': '10/m'
},

版本

源碼流程

1.和認(rèn)證的流程一樣,進(jìn)入initial(request)
在認(rèn)證,權(quán)限,節(jié)流前先執(zhí)行了這兩句函數(shù),獲取到version,scheme,并分別賦值給request對(duì)象的version, versioning_scheme屬性

獲取版本(version)和scheme

        version, scheme = self.determine_version(request, *args, **kwargs) 
        request.version, request.versioning_scheme = version, scheme


進(jìn)入determine_version()函數(shù)
  scheme = self.versioning_class()
        return (scheme.determine_version(request, *args, **kwargs), scheme)


在這里獲取到scheme就是api_settings.DEFAULT_VERSIONING_CLASS,系統(tǒng)默認(rèn)版本控制類(lèi),那scheme.determine_version(request, *args, kwargs) 就是該類(lèi)下的一個(gè)方法
查看rest_framework庫(kù)的一個(gè)自帶類(lèi)中的determine_version方法
class QueryParameterVersioning(BaseVersioning):
    """
    GET /something/?version=0.1 HTTP/1.1
    Host: example.com
    Accept: application/json
    """
    invalid_version_message = _('Invalid version in query parameter.')

    def determine_version(self, request, *args, **kwargs):
        version = request.query_params.get(self.version_param, self.default_version)
    if not self.is_allowed_version(version):
        raise exceptions.NotFound(self.invalid_version_message)
    return version

返回的是版本號(hào)。于是version, scheme分別是版本號(hào)和一個(gè)版本控制類(lèi),并分別賦值給request對(duì)象的version, versioning_scheme屬性。
使用

內(nèi)置類(lèi)的使用
1.放到url后作為get參數(shù)

http://127.0.0.1:8000/api/users/?version=v1
from rest_framework.versioning import QueryParameterVersioning
class UsersView(APIView):
    versioning_class = QueryParameterVersioning

    def get(self, request, *args, **kwargs):
        # 獲取版本
        self.dispatch
        print(request.version)
        # 獲取版本處理對(duì)象
        # print(request.versioning_scheme)
        # u1 = request.versioning_scheme.reverse('api:uuu', request=request)
        # print("u1:", u1)
        # u2 = reverse('api:uuu', kwargs={'version': 1})
        # print("u2:", u2)
        return HttpResponse('用戶列表')

2.用正則匹配

 re_path(r'^(?P<version>[v1|v2]+)/users/', views.UsersView.as_view(), name="uuu"),
from rest_framework.versioning import URLPathVersioning
class UsersView(APIView):
    versioning_class = URLPathVersioning

    def get(self, request, *args, **kwargs):
        # 獲取版本
        self.dispatch
        print(request.version)
        # 獲取版本處理對(duì)象
        # print(request.versioning_scheme)
        # u1 = request.versioning_scheme.reverse('api:uuu', request=request)
        # print("u1:", u1)
        # u2 = reverse('api:uuu', kwargs={'version': 1})
        # print("u2:", u2)
        return HttpResponse('用戶列表')

request.versioning_scheme.reverse方法可以獲取路由,是drf中的方法
django.urls.reverse 是django中的反向獲取路由方法
u1: http://127.0.0.1:8000/api/v1/users/
u2: /api/1/users/

解析器

1.本質(zhì)
· 請(qǐng)求頭
· 狀態(tài)嗎
· 請(qǐng)求方法

2.源碼流程
· dispatch : request封裝
· request.data

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容