博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
django Rest Framework----认证/访问权限控制/访问频率限制 执行流程 Authentication/Permissions/Throttling 源码分析...
阅读量:5159 次
发布时间:2019-06-13

本文共 7878 字,大约阅读时间需要 26 分钟。

url:

url(r'books/$',views.BookView.as_view({
'get':'list','post':'create'})) 为例

当django启动的时候,会调用执行view.BookView.as_view()方法,拿到as_view的返回值view

url(r'books/$',View.view)

当用户访问books/的时候,会执行View.view(). 执行APIView.dispatch()

当用户访问books/时,django拿到request,然后对request进行了重新封装 并且进行用户认证
url(r'books/$',View.view) --->  执行 self.dispatch()

APIView.dispatch()

def dispatch(self, request, *args, **kwargs):       ...        request = self.initialize_request(request, *args, **kwargs)        self.request = request        try:            self.initial(request, *args, **kwargs)        ....

 request = self.initialize_request(request, *args, **kwargs)

def initialize_request(self, request, *args, **kwargs):        #返回一个Request对象        return Request(            ...            authenticators=self.get_authenticators(),            ...        )    def get_authenticators(self):         # 循环视图类authentication_classes         # 使用列表推导式,生成每一个实例对象        return [auth() for auth in self.authentication_classes]

 

回到dispatch()中,继续向下执行self.inital(request,*args,**kwags)

def initial(self, request, *args, **kwargs):          ...        # 认证        self.perform_authentication(request)        # 权限        self.check_permissions(request)        # 访问频率限制        self.check_throttles(request)

对于用户认证,我们主要看 self.perform_authentication(request) 干了什么

def perform_authentication(self, request):        # 调用了request.user    属性方法        request.user
@propertydef user(self):        if not hasattr(self, '_user'):            with wrap_attributeerrors():                # 调用  _authenticate  此时的self是request对象                self._authenticate()        return self._userdef _authenticate(self):            # 此时的self是request ,authenticator每一个验证类对象            for authenticator in self.authenticators:                try:                    # 使用authenticator调用它的authenticate() 返回一个元组                    #元组的第一个值是request.user,第二个值是request.auth                    user_auth_tuple = authenticator.authenticate(self)                except exceptions.APIException:                    # 如果没有验证通过,抛出异常                    self._not_authenticated()                    raise                # 如果 user_auth_tuple  不为空的话,证明authenticator.authenticate(self) 返回了数据                #  **** 有多个验证类的话,最后一个认证类返回值,其他验证类不要返回                # 否则,这个验证类之后的所有验证类都不会被执行                # 如果返回值不为None,赋值后 将会跳出循环                if user_auth_tuple is not None:                    self._authenticator = authenticator                    # 进行赋值                    self.user, self.auth = user_auth_tuple                    # 跳出for循环, 验证通过                    return            self._not_authenticated()

 

认证执行流程:

1. 查看settings.py中是否配置了作用于全局的REST_FRAMEWORK配置,如果有,就是用全局

2. 如果settings.py没有配置,就去视图类中(本例是BookView)查看是否配置了authentication_classes

3. 以上都没有配置,就是用默认的,在APIView中配置

 

自定义一个认证

class BookAuthen():    def authenticate(self,request):        #获取token,检验token是否正确,如果正确则,验证通过        #否则抛出异常        token_val = request.GET.get('token')        user_obj = models.User.objects.filter(token__token=token_val).first()        if user_obj:            return user_obj.name,token_val        else:            raise exceptions.AuthenticationFailed    def authenticate_header(self,request):        passclass BookView(ModelViewSet):    # 如果提供,就执行BookAuthen,如果没有提供,使用APIView提供的    authentication_classes = [BookAuthen,]    queryset = models.Book.objects.all()    serializer_class = BookModelSerializer

全局配置(settings.py):

REST_FRAMEWORK= {        'DEFAULT_AUTHENTICATION_CLASSES': (            'bookmanage.auth.authen.BookAuthen',            'rest_framework.authentication.SessionAuthentication',            'rest_framework.authentication.BasicAuthentication'        )    }

默认配置(APIView):

class APIView(View):        ...        # 首先api_settings没有DEFAULT_AUTHENTICATION_CLASSES  所以会调用apisetting.__getattr__()        authentication_classes = api_settings.DEFAULT_AUTHENTICATION_CLASSES        ...

 

二、访问频率限制

访问频率限制和用户认证流程几乎相同 

首先看url

url(r'books/$',views.BookView.as_view({
'get':'list','post':'create'})) 为例 django启动时 去执行BookView.as_view()方法--->APIView.as_view()-->最终返回的是APIView.view url(r'books/$',views.BookView.as_view({
'get':'list','post':'create'})) url(r'books/$',APIView.view) 用户访问时
执行APIView.view(),其中它调用了父类的as_view(),实际上什么都没做     执行self.dispatch(),执行的是APIView.dispatch()     self.initial(request, *args, **kwargs)         调用了 --> self.check_throttles(request)  #此时的self是BookView视图类

dispatch()中,self.inital(request,*args,**kwags)  -->  self.check_throttles(request)

def get_throttles(self):     """      遍历视图类中的throttle_classes       拿到每一个自定义访问频率限制类的实例对象      """      return [throttle() for throttle in self.throttle_classes] def check_throttles(self, request):    for throttle in self.get_throttles():         # 拿到自定义访问频率限制类的实例对象,调用allow_request()          if not throttle.allow_request(request, self):                 # 如果没有通过验证,执行self.throttled()抛出异常                  self.throttled(request, throttle.wait())

自定义访问频率限制类

# 限制IP频繁访问    class VisitThrottle(object):        detail = "访问频率不正常"        def allow_request(self,request, obj):            now_time = str(time.time())            if request.session.get('visittime'):                visited = request.session.get('visittime')                visited.append(now_time)                request.session['visittime'] = visited                if len(visited) >= 20:                    first = visited[-2]                    last = visited[-1]                    time_ = time.gmtime(float(last) - float(first))                    print(time_)                    if time_.tm_min > 1:                        request.session['visittime'] = []                        return True                    elif time_.tm_min <= 1:                        raise exceptions.Throttled(detail=self.detail)            else:                request.session['visittime'] = [now_time,]            print(request.META.get('REMOTE_ADDR'))            return True    class BookView(ModelViewSet):        #在视图类中配置自定义频率访问组件        throttle_classes = [VisitThrottle]        queryset = models.Book.objects.all()        serializer_class = BookModelSerializer

默认访问频率限制

由于每一个视图类都是继承自APIView,如果配置throttle_classes,就使用自定义的如果没配置throttle_classes,APIView配置了默认的
class APIView(View):        ....        # 由于api_settings没有DEFAULT_THROTTLE_CLASSES,会调用api_setting的__getattr__()        throttle_classes = api_settings.DEFAULT_THROTTLE_CLASSES        ....    api_settings = APISettings(None, DEFAULTS, IMPORT_STRINGS)    class APISettings(object):        def __init__(self, user_settings=None, defaults=None, import_strings=None):            #不会进入            if user_settings:                self._user_settings = self.__check_user_settings(user_settings)            # 将DEFAULTS 复制给  self.defaults            self.defaults = defaults or DEFAULTS        @property        def user_settings(self):            if not hasattr(self, '_user_settings'):                self._user_settings = getattr(settings, 'REST_FRAMEWORK', {})            return self._user_settings        def __getattr__(self, attr):            if attr not in self.defaults:                raise AttributeError("Invalid API setting: '%s'" % attr)            try:                # self.user_settings : 它从settings.py中取找 是否存在 REST_FRAMEWORK配置项                # 如果有,因为他是一个字典,取[DEFAULT_THROTTLE_CLASSES]对应的路径自定义访问频率类                val = self.user_settings[attr]            except KeyError:                # 如果没有,就使用默认的                # self.defaults[DEFAULT_THROTTLE_CLASSES]                val = self.defaults[attr]            ....            return val

全局配置

1. 此时,应该将自定义的访问频率组件提取出来单独放在一个py文件中 2. 指定路径类 3. 所有的url访问都会进行访问频率限制
REST_FRAMEWORK= {        'DEFAULT_AUTHENTICATION_CLASSES': (            'bookmanage.auth.authen.BookAuthen',        ),        'DEFAULT_THROTTLE_CLASSES':(            'bookmanage.auth.throttle.VisitThrottle'        )    }

 

转载于:https://www.cnblogs.com/weihengblog/p/9212177.html

你可能感兴趣的文章
input中的name,value以及label中的for
查看>>
静态库制作-混编(工程是oc为基础)
查看>>
jQuery 显示加载更多
查看>>
代理模式
查看>>
Confluence 6 系统运行信息中的 JVM 内存使用情况
查看>>
Confluence 6 升级以后
查看>>
用JS实现版面拖拽效果
查看>>
二丶CSS
查看>>
《avascript 高级程序设计(第三版)》 ---第二章 在HTML中使用Javascript
查看>>
Hibernate主键生成策略
查看>>
Crushing Machinery - Strong Support of Cement Enterprise
查看>>
AsyncTask
查看>>
Django框架(十九)—— drf:序列化组件(serializer)
查看>>
JS一些概念知识及参考链接
查看>>
关于JS中&&和||用法技巧
查看>>
suoi14 子树查找 (dfs)
查看>>
作业5 四则运算 测试与封装 5.1
查看>>
实验7
查看>>
双系统更改启动顺序
查看>>
用参数较少的函数替换参数较多的函数
查看>>