django中间件


django系列之 drf身份认证

Django中间件

1、简介

中间件是 Django 请求/响应处理的钩子框架。它是一个轻量级的、低级的“插件”系统,用于全局改变 Django 的输入或输出,在其他web框架中,有的叫管道或者httphandle,Django中很多功能都是通过中间件实现的,实际上中间件就是一个类,在请求到来和结束后,django会根据自己的规则在合适的时机执行中间件中相应的方法.
django的生命周期:
nigx -->wsgi–>middleware–>urls–>views–>orm–>db

在工程中的settings.py中由变量MIDDLEWARE控制,请求从上到下依次穿过中间件,每个中间件中都可以有5个方法:

  • process_request(self,request)#请求最开始执行的方法

  • process_response(self,request, response)#请求返回时候执行的方法

  • process_view(self, request, callback,callback_args, callback_kwargs)#请求到达views视图之前执行的方法

  • process_exception(self, request, exception) # 默认不执行,除非Views方法出错

  • process_template_response(self,request,response) #
    默认不执行,除非Views中的函数返回的对象中,具有render方法(区别于模板渲染的render)
    类似于栈,从上往下执行,从下而上返回

MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
]

这里介绍下美国中间件的功能:

  • SecurityMiddleware:为request/response提供了几种安全改进,无它不安全
  • SessionMiddleware:开启session会话支持,
  • CommonMiddleware:基于APPEND_SLASH和PREPEND_WWW的设置来重写URL,如果APPEND_SLASH设为True,并且初始URL 没有以斜线结尾以及在URLconf 中没找到对应定义,这时形成一个斜线结尾的新URL;如果PREPEND_WWW设为True,前面缺少 www.的url将会被重定向到相同但是以一个www.开头的url。
  • CsrfViewMiddleware:添加跨站点请求伪造的保护,通过向POST表单添加一个隐藏的表单字段,并检查请求中是否有正确的值
  • AuthenticationMiddleware:在视图函数执行前向每个接收到的user对象添加HttpRequest属性,表示当前登录的用户
  • MessageMiddleware:开启基于Cookie和会话的消息支持
  • XFrameOptionsMiddleware:对点击劫持的保护

2、请求在中间件中的方法请求过程

  • 1,用户请求先中间件,由上到下先后执行每个中间件process_request方法;
  • 2,执行完每个中间件的process_request方法之后,请求到达urls路由关系映射;
  • 3,到达urls路由以后,由下至上执行每个中间件的process_views方法;
  • 4,执行完process_views,请求到达views函数,此时若views函数有错误信息,则由下到上执行process_exception方法,直到错误发生停止;
  • 5,如果views中没有出错,那么请求由下到上执行每个中间件的process_response方法,返回响应客户;

3、自定义中间件

自定义中间件,我们至少包括两个方法,一个是process_request,还有一个是process_response,创建一个py文件,在工程中创建MyMiddleWare目录(与tempates同级),创建文件md.py,注意使用process_response必须返回response:

class ApiLoggingMiddleware(MiddlewareMixin):
    
    def process_request(self, request):
        print( '''请求时执行''')

    def process_response(self, request, response):

        print(   """视图函数调用之后,response返回浏览器之前""")
        
        
    def process_exception(self, request, exception):
        print('视图发生异常')

请求:127.0.0.0:8000/admin/
发生了一个错误

Traceback (most recent call last):
  File "E:\py38\lib\site-packages\django\core\handlers\exception.py", line 34, in inner
    response = get_response(request)
  File "E:\py38\lib\site-packages\django\utils\deprecation.py", line 96, in __call__
    response = self.process_response(request, response)
  File "E:\py38\lib\site-packages\django\middleware\common.py", line 106, in process_response
    if response.status_code == 404:
AttributeError: 'NoneType' object has no attribute 'status_code'
[26/Oct/2020 18:09:22] "POST /user/login/ HTTP/1.1" 500 60687

我们看一下源码

 def process_response(self, request, response):
        """
        When the status code of the response is 404, it may redirect to a path
        with an appended slash if should_redirect_with_slash() returns True.
        """
        # If the given URL is "Not Found", then check if we should redirect to
        # a path with a slash appended.
        if response.status_code == 404:
            if self.should_redirect_with_slash(request):
                return self.response_redirect_class(self.get_full_path_with_slash(request))

        # Add the Content-Length header to non-streaming responses if not
        # already set.
        if not response.streaming and not response.has_header('Content-Length'):
            response['Content-Length'] = str(len(response.content))

        return response#这里必须返回response

4,源码解析

我们继承的类

class MiddlewareMixin:
    def __init__(self, get_response=None):
        self.get_response = get_response
        super().__init__()

    def __call__(self, request): #实例化后调用
        response = None
        if hasattr(self, 'process_request'):
            response = self.process_request(request)
        response = response or self.get_response(request)
        if hasattr(self, 'process_response'):
            response = self.process_response(request, response)
        return response

我们调用的类


class CommonMiddleware(MiddlewareMixin):
    """
    "Common" middleware for taking care of some basic operations:

        - Forbid access to User-Agents in settings.DISALLOWED_USER_AGENTS

        - URL rewriting: Based on the APPEND_SLASH and PREPEND_WWW settings,
          append missing slashes and/or prepends missing "www."s.

            - If APPEND_SLASH is set and the initial URL doesn't end with a
              slash, and it is not found in urlpatterns, form a new URL by
              appending a slash at the end. If this new URL is found in
              urlpatterns, return an HTTP redirect to this new URL; otherwise
              process the initial URL as usual.

          This behavior can be customized by subclassing CommonMiddleware and
          overriding the response_redirect_class attribute.
    """

    response_redirect_class = HttpResponsePermanentRedirect

    def process_request(self, request):
        """
        Check for denied User-Agents and rewrite the URL based on
        settings.APPEND_SLASH and settings.PREPEND_WWW
        """

        # Check for denied User-Agents
        user_agent = request.META.get('HTTP_USER_AGENT')
        if user_agent is not None:
            for user_agent_regex in settings.DISALLOWED_USER_AGENTS:
                if user_agent_regex.search(user_agent):
                    raise PermissionDenied('Forbidden user agent')

        # Check for a redirect based on settings.PREPEND_WWW
        host = request.get_host()
        must_prepend = settings.PREPEND_WWW and host and not host.startswith('www.')
        redirect_url = ('%s://www.%s' % (request.scheme, host)) if must_prepend else ''

        # Check if a slash should be appended
        if self.should_redirect_with_slash(request):
            path = self.get_full_path_with_slash(request)
        else:
            path = request.get_full_path()

        # Return a redirect if necessary
        if redirect_url or path != request.get_full_path():
            redirect_url += path
            return self.response_redirect_class(redirect_url)
            ......
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值