欧美一区二区三区老妇人-欧美做爰猛烈大尺度电-99久久夜色精品国产亚洲a-亚洲福利视频一区二区

drf 認證、權限、頻率限制以及其源碼

內容概要

  • token認證小練習
  • 認證
  • 權限
  • 頻率

內容詳細

登錄攜帶token認證小練習

models.py:

在穆棱等地區(qū),都構建了全面的區(qū)域性戰(zhàn)略布局,加強發(fā)展的系統(tǒng)性、市場前瞻性、產(chǎn)品創(chuàng)新能力,以專注、極致的服務理念,為客戶提供做網(wǎng)站、網(wǎng)站建設 網(wǎng)站設計制作按需定制,公司網(wǎng)站建設,企業(yè)網(wǎng)站建設,高端網(wǎng)站設計,全網(wǎng)整合營銷推廣,成都外貿網(wǎng)站制作,穆棱網(wǎng)站建設費用合理。

class User(models.Model):
    username = models.CharField(max_length=32)
    password = models.CharField(max_length=32)


class UserToken(models.Model):
    user = models.OneToOneField(to='User', on_delete=models.CASCADE)
    token = models.CharField(max_length=64)

views.py:

from rest_framework.response import Response
from rest_framework.viewsets import ModelViewSet
import uuid

class BookViewSet(ModelViewSet):
    queryset = Book.objects
    serializer_class = BookModelSerializer

    @action(methods=['GET', 'POST'], detail=False)
    def login(self, request):
        username = request.data.get('username')
        password = request.data.get('password')
        user = models.User.objects.filter(username=username, password=password).first()
        if user:
            token = str(uuid.uuid4())
            models.UserToken.objects.update_or_create(user=user, defaults={'token': token})
            return Response({'code': 100, 'msg': '登錄成功', 'token': token})
        return Response({'code': 101, 'msg': '用戶名或密碼錯誤'})

urls.py:

from rest_framework.routers import DefaultRouter, SimpleRouter

router = DefaultRouter()
router.register('books4', views.BookViewSet)

urlpatterns = [
    path('admin/', admin.site.urls),
]
urlpatterns += router.urls

開始學習之前,先搞清楚 drf 認證、權限、頻率三大功能是在哪里實現(xiàn)的?

APIView 源碼中實現(xiàn),所有繼承 APIView 的類都可以實現(xiàn)三大認證

APIView 的類的 as_view 返回 view 函數(shù)的內存地址,view運行后調用了 APIView中的 dispatch方法,三大認證在 self.initial(request, *args, **kwargs) 函數(shù)中調用

    def dispatch(self, request, *args, **kwargs):
        request = self.initialize_request(request, *args, **kwargs)
        try:
            self.initial(request, *args, **kwargs)
        except Exception as exc:
            response = self.handle_exception(exc)

APIView --> initial

    def initial(self, request, *args, **kwargs):
        self.perform_authentication(request)  # 認證
        self.check_permissions(request)  # 權限
        self.check_throttles(request)  # 頻率

認證源碼

APIView --> perform_authentication(request)

源碼中只返回了登錄用戶或者匿名用戶對象

該方法調用了 request.user ,也就是重寫后的 request 屬性中的 user,我們知道那里的 user有被調用觸發(fā)的方法 和 被賦值觸發(fā)的方法

    def perform_authentication(self, request):
        """
        `request.user` or `request.auth` is accessed.
        """
        request.user

轉到重寫 request 對象的Request類中:

Request --> user(property)

可以看到調用的是 Request類中的 _authenticate()

    @property
    def user(self):
        if not hasattr(self, '_user'):
            with wrap_attributeerrors():
                self._authenticate()
        return self._user

Request --> _authenticate 核心代碼

該方法循環(huán) Request類中的 authenticators列表(認證類列表)

調用認證類 authenticator 中的 authenticate(self) 方法,并放回元組user_auth_tuple,包含登錄用戶對象(user)和 auth

如果 user_auth_tuple 不為 None,則 request 對象便獲取了user對象和 auth對象

  • 我們在自定義認證類時,就要重寫 authenticate(self) 方法,并放回 user對象和 auth對象
    def _authenticate(self):
        for authenticator in self.authenticators:
            try:
                user_auth_tuple = authenticator.authenticate(self)  # 調用類中的authenticate方法
            except exceptions.APIException:
                self._not_authenticated()
                raise

            if user_auth_tuple is not None:
                self._authenticator = authenticator
                self.user, self.auth = user_auth_tuple
                return
        self._not_authenticated()

authenticators 怎么來的?

可以看出,authenticatorsRequest類實例化時傳進來的參數(shù),那么我們就得回到APIView類中的 initialize_request(self, request, *args, **kwargs) 方法,因為是在那里實例化了 Request

class Request:
    def __init__(self, request, parsers=None, authenticators=None,
                 negotiator=None, parser_context=None):
        self.authenticators = authenticators or ()

APIView --> initialize_request

可以看到調用了自己的 get_authenticators() 方法

    def initialize_request(self, request, *args, **kwargs):
        return Request(
            request,
            parsers=self.get_parsers(),
            authenticators=self.get_authenticators(),
            negotiator=self.get_content_negotiator(),
            parser_context=parser_context
        )

APIView --> get_authenticators()

這是個列表生成式,從視圖函數(shù)類中的認證類列表 authentication_classes 中取出一個個認證類加括號實例化為對象,并存在類表中放回,那么get_authenticators() 方法放回的是一個認證類對象的列表

    def get_authenticators(self):
        """
        Instantiates and returns the list of authenticators that this view can use.
        """
        return [auth() for auth in self.authentication_classes]

繞來繞去,最終明白,我們可以在視圖類中定義 authentication_classes 列表,存放認證類,在觸發(fā)視圖函數(shù)類時就會執(zhí)行列表中認證類重寫的 authenticate(self)方法,并放回登錄的用戶對象和auth

權限源碼

APIView --> check_permissions(request)

get_permissions()是獲取認證類對象列表

has_permission(request, self) 是我們自定義權限類時要改寫的方法,返回True或False

    def check_permissions(self, request):
        for permission in self.get_permissions():
            if not permission.has_permission(request, self):
                self.permission_denied(
                    request,
                    message=getattr(permission, 'message', None),
                    code=getattr(permission, 'code', None)
                )

頻率源碼

APIView --> check_throttles(request)

    def check_throttles(self, request):
        throttle_durations = []
        for throttle in self.get_throttles():
            if not throttle.allow_request(request, self):
                throttle_durations.append(throttle.wait())
        if throttle_durations:
            durations = [
                duration for duration in throttle_durations
                if duration is not None
            ]
            duration = max(durations, default=None)
            self.throttled(request, duration)

在調用自定義認證類時視圖類中需要提前定義的參數(shù)

class APIView(View):

    # The following policies may be set at either globally, or per-view.
    renderer_classes = api_settings.DEFAULT_RENDERER_CLASSES
    parser_classes = api_settings.DEFAULT_PARSER_CLASSES
    authentication_classes = api_settings.DEFAULT_AUTHENTICATION_CLASSES  # 認證類列表
    throttle_classes = api_settings.DEFAULT_THROTTLE_CLASSES              # 頻率限制類
    permission_classes = api_settings.DEFAULT_PERMISSION_CLASSES          # 權限類
    content_negotiation_class = api_settings.DEFAULT_CONTENT_NEGOTIATION_CLASS
    metadata_class = api_settings.DEFAULT_METADATA_CLASS
    versioning_class = api_settings.DEFAULT_VERSIONING_CLASS

三個認證類在 drf 配置文件中的配置

DEFAULTS = {
    'DEFAULT_AUTHENTICATION_CLASSES': [
        'rest_framework.authentication.SessionAuthentication',
        'rest_framework.authentication.BasicAuthentication'
    ],
    'DEFAULT_PERMISSION_CLASSES': [
        'rest_framework.permissions.AllowAny',
    ],
    'DEFAULT_THROTTLE_CLASSES': [],
}

先寫一個登錄視圖類

校驗過登錄用戶數(shù)據(jù)之后把token信息存到usertoken表中

class LoginViewSet(ModelViewSet):
    queryset = models.User.objects
    serializer_class = UserSerializer

    @action(methods=['POST'], detail=False)  # api 要多寫一個 login/
    def login(self, request):
        username = request.data.get('username')
        password = request.data.get('password')
        user_obj = models.User.objects.filter(username=username, password=password).first()
        if not user_obj:
            return Response({'code': 1001, 'msg': '該用戶不存在'})
        uuid_str = str(uuid.uuid4())
        # 過濾條件中user=user的對象,而不是pk
        models.UserToken.objects.update_or_create(user=user_obj, defaults={'token': uuid_str})  # 別漏寫default后的字典
        return Response({'code': 1000, 'msg': '登錄成功', 'token': uuid_str})

認證

1、新建一個認證模塊,寫一個認證類繼承 BaseAuthentication(多態(tài)),重寫authenticate方法,在方法中校驗是否登錄,是則返回兩個值(request.userrequest.auth

from rest_framework.authentication import BaseAuthentication


# 登錄認證
class LoginAuth(BaseAuthentication):
    def authenticate(self, request):
        token = request.data.get('token')
        is_login = models.UserToken.objects.filter(token=token).first()
        if not is_login:
            raise AuthenticationFailed('您沒有登錄')
        return is_login.user, token

2、在視圖類中書寫 authentication_classes,存放導入進來的認證類

  • 局部配置
from app01.authentications import LoginAuth, ChangePermission

class BookViewSet(ViewSetMixin, ListAPIView):
    queryset = models.Book.objects
    serializer_class = BookModelSerializer
    authentication_classes = [LoginAuth, ]
  • 局部禁用
class BookViewSet(ViewSetMixin, ListAPIView):
    queryset = models.Book.objects
    serializer_class = BookModelSerializer
    authentication_classes = []

3、全局配置(在項目文件夾下的 settings.py 文件中配置)

REST_FRAMEWORK = {
    'DEFAULT_AUTHENTICATION_CLASSES': [
        'app01.authentications.LoginAuth',
    ],
}

權限

1、在認證模塊中,寫一個權限類繼承 BasePermission(多態(tài)),重寫has_permission方法,在方法中校驗該用戶的用戶類型,是否有權限執(zhí)行該視圖類,返回 True 或者 False, 還可以自定義報錯信息 self.message

from rest_framework.permissions import BasePermission

class ChangePermission(BasePermission):
    def has_permission(self, request, view):
        self.message = '您是%s,沒有修改權限' % request.user.get_user_type_display()  # 根據(jù)源碼,可以修改權限的提示信息
        user_type = request.user.user_type
        if user_type != 1:
            return False
        return True

2、在視圖類中書寫 permission_classes,存放導入進來的權限類

  • 局部配置

注意:在定義權限認證類前需要先定義登錄認證類,否則沒有用戶對象 requset.user 來做權限認證

from app01.authentications import LoginAuth, ChangePermission

class BookViewChange(ViewSetMixin, CreateAPIView, RetrieveUpdateDestroyAPIView):
    queryset = models.Book.objects
    serializer_class = BookModelSerializer
    authentication_classes = [LoginAuth, ]
    permission_classes = [ChangePermission, ]
  • 局部禁用
class BookViewChange(ViewSetMixin, CreateAPIView, RetrieveUpdateDestroyAPIView):
    queryset = models.Book.objects
    serializer_class = BookModelSerializer
    authentication_classes = [LoginAuth, ]
    permission_classes = []

3、全局配置(在項目文件夾下的 settings.py 文件中配置)

REST_FRAMEWORK = {
    'DEFAULT_PERMISSION_CLASSES': [
        'app01.authentications.ChangePermission',
    ],
}

頻率

1、在認證模塊中,寫一個頻率限制類繼承 SimpleRateThrottle(多態(tài)),重寫類屬性 scopeget_cache_key方法,該方法返回什么,就以什么為限制,scope配置文件中要用

from rest_framework.throttling import SimpleRateThrottle

# 頻率限制
class IPThrottling(SimpleRateThrottle):
    scope = 'minute_3'

    # 返回什么就以什么做限制
    def get_cache_key(self, request, view):
        # return request.META.get('REMOTE_ADDR')  # 客戶端ip地址
        return request.user.id  # 用戶id

2、與其它兩個認證不同,他需要在項目配置文件中配置:

REST_FRAMEWORK = [
    'DEFAULT_THROTTLE_RATES': {
        'minute_3': '3/m'  # minute_3是scope的字符串,一分鐘訪問3次
        'minute_5':'5/m'
    }
]

2、在視圖類中書寫 throttle_classes,存放導入進來的權限類

  • 局部配置
class BookViewSet(ViewSetMixin, ListAPIView):
    queryset = models.Book.objects
    serializer_class = BookModelSerializer
    authentication_classes = [LoginAuth, ]
    throttle_classes = [IPThrottling, ]
  • 局部禁用
class BookViewSet(ViewSetMixin, ListAPIView):
    queryset = models.Book.objects
    serializer_class = BookModelSerializer
    authentication_classes = [LoginAuth, ]
    throttle_classes = []

3、全局配置(在項目文件夾下的 settings.py 文件中配置)

REST_FRAMEWORK = {
    'DEFAULT_THROTTLE_CLASSES': [
        'app01.authentications.IPThrottling'
    ],
    'DEFAULT_THROTTLE_RATES': {
        'minute_3': '3/m',  # minute_3是scope的字符串,一分鐘訪問3次
        # 'minute_5': '5/m'
    }
}

當前標題:drf 認證、權限、頻率限制以及其源碼
轉載源于:http://chinadenli.net/article36/dsoghsg.html

成都網(wǎng)站建設公司_創(chuàng)新互聯(lián),為您提供關鍵詞優(yōu)化、網(wǎng)站導航、網(wǎng)站策劃、全網(wǎng)營銷推廣、外貿建站、網(wǎng)站改版

廣告

聲明:本網(wǎng)站發(fā)布的內容(圖片、視頻和文字)以用戶投稿、用戶轉載內容為主,如果涉及侵權請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內容未經(jīng)允許不得轉載,或轉載時需注明來源: 創(chuàng)新互聯(lián)

h5響應式網(wǎng)站建設
国产亚洲二区精品美女久久 | 国产日产欧美精品大秀| 蜜桃传媒视频麻豆第一区| 激情亚洲一区国产精品久久| 久久这里只有精品中文字幕| av在线免费播放一区二区| 日韩精品综合免费视频| 激情中文字幕在线观看| 久久热这里只有精品视频| 久久精品国产亚洲av麻豆| 国产中文字幕久久黄色片| 国产福利一区二区三区四区| 人妻久久一区二区三区精品99| 国产欧美一区二区另类精品| 中文字幕免费观看亚洲视频| 日韩精品中文字幕亚洲| 偷自拍亚洲欧美一区二页| 中文字幕日韩欧美亚洲午夜| 欧美又大又黄刺激视频| 99久久精品一区二区国产| 国产欧美日韩在线精品一二区| 精品少妇一区二区视频| 日韩成人h视频在线观看| 一二区不卡不卡在线观看| 日韩欧美国产三级在线观看| 日韩国产亚洲一区二区三区| 99福利一区二区视频| 亚洲视频一区二区久久久| 精品久久少妇激情视频| 中文字幕亚洲精品乱码加勒比| 亚洲一区二区三区精选| 欧美一级内射一色桃子| 亚洲午夜精品视频在线| 黑丝袜美女老师的小逼逼| 欧美亚洲另类久久久精品| 欧美午夜性刺激在线观看| 国产精品视频久久一区| 亚洲精选91福利在线观看 | 国产又色又爽又黄的精品视频| 欧美午夜一级特黄大片| 精品熟女少妇一区二区三区|