Django 框架6- 中间件(MiddleWare)

一、什么是Django中间件?

    1、中间件是Django处理请求/响应的钩子框架。这是一个轻,低层次的“插件”系统,用于全局改变Django和客户端的输入和输出。

    2、我的理解,给Django加一个装饰器,客户端向Django发送请求时,先由中间件处理一下,再决定是否交给Views处理

    3、一般处理哪些任务?请求的日志、用户登录认证、请求地址跳转、IP地址过滤,等等


二、中间件在哪里设置?

    project下,project包下的settings.py文件,MIDDLEWARE列表,添加或删除列表项。


三、多个中间件的运行方式?

    中间件列表运行从前到后,遇到错误停止,返回数据从后到前。类似列表的先进后出。


四、中间件在一次请求中的运行时间点?

    1、Django服务启动时,中件间初始化

1.png

    2、客户端请求时,中件间调用

2.png


五、自已怎么做一个中间件?

    1、新建一个xxxxxx.py的python文件,可以放在Project任意位置,比如我这里新建midtest.py存到project根目录。

    2、在midtest.py里创建中间件函数或类

from django.utils.deprecation import MiddlewareMixin
# 导入中间件类

class MyMiddleware(MiddlewareMixin):
    # 自定义类继承中间件类
    def process_request(self,request):
    # 重写中间件方法
        print("---process_request---")

    3、把创建的中间件添加到settings.py的MIDDLEWARE列表

MIDDLEWARE=["midtest.MYMiddleware",
           ]


六、中间件进阶:


        1、自定义中间件的五个方法和执行顺序:

            process_request():客户端请求时执行,然后请求urls.py

            process_view():urls.py之后,views.py之前

            process_template_response():views.py之后

            process_exception():捕获views.py的错误,所以是在views.py之后

            process_response():在exception之后运行

        2、代码实例

from django.utils.deprecation import MiddlewareMixin
class MyMiddleware(MiddlewareMixin):
    # 例子中列举了所有方法,但使用的时候可以只用一个
    # 当然也可以通过class MyMid: __init__和__call__来改写,参考继承的MiddelwareMixin类的写法
    
    def process_request(self, request):
    # request参数,客户端的请求
    # 可以设置验证登陆、IP阻止列表等功能
    
        # 1、-----通过session验证登陆-----
        if request.path_info == '/login/':    # 请求login正常执行
            return
        elif not request.session.get('k1', None): # 请求其它页面判断未登陆跳转到login
            return redirect('/login/')
    
        # 2、-----设置拒绝访问的客户端IP-----
        refuse_ip=["172.0.0.1"]
        if request.META.get('HTTP_X_FORWARDED_FOR', None):    # 'HTTP_X_FORWARDED_FOR'使用反向代理时,寻找用户真实IP
            ip = request.META['HTTP_X_FORWARDED_FOR']
        else:
            ip = request.META['REMOTE_ADDR']                  # 如果'HTTP_X_FORWARDED_FOR'不存在则获取REMOTE_ADDR
        
        if ip in refuse_ip:                                   # 判断IP是否在拒绝列表里
            return HttpResponse("干啥亏心事了,不让你登陆!")
        
    
    def process_view(self, response, view_func, *args, **kwargs):
        # request客户端请求
        # view_func 请求的视图函数
        # *args,**kwargs    请求时附带的参数
        
        
    def process_exception(self, request, response):
        # 如果views.py函数有报错,执行
        # request客户端请求

    

七、CSRF中间件


    跨站请求伪造(英语:Cross-site request forgery),也被称为 one-click attack 或者 session riding,通常缩写为 CSRF 或者 XSRF, 是一种挟制用户在当前已登录的Web应用程序上执行非本意的操作的***方法。跟跨网站脚本(XSS)相比,XSS 利用的是用户对指定网站的信任,CSRF 利用的是网站对用户网页浏览器的信任。

    

    解决方法:

    1、检查HTTP的Referer字段

    2、添加校验Token

    

    Django的CSRF校验:

    1、django使用的是添加校验的Token,

    2、方法一:使用的是中间件'django.middleware.csrf.CsrfViewMiddleware'

          方法二:服务器向客户端发送一个加密的Token,来进行客户认证

    3、HTML的From中添加标签{% csrf_token %}

    4、CSRF源码:

class CsrfViewMiddleware(MiddlewareMixin):
    def _accept(self, request):
        request.csrf_processing_done = True
        return None
    def _reject(self, request, reason):
        logger.warning(
            'Forbidden (%s): %s', reason, request.path,
            extra={
                'status_code': 403,
                'request': request,
            }
        )
        return _get_failure_view()(request, reason=reason)
    def _get_token(self, request):
        if settings.CSRF_USE_SESSIONS:
            try:
                return request.session.get(CSRF_SESSION_KEY)
            except AttributeError:
                raise ImproperlyConfigured(
                    'CSRF_USE_SESSIONS is enabled, but request.session is not '
                    'set. SessionMiddleware must appear before CsrfViewMiddleware '
                    'in MIDDLEWARE%s.' % ('_CLASSES' if settings.MIDDLEWARE is None else '')
                )
        else:
            try:
                cookie_token = request.COOKIES[settings.CSRF_COOKIE_NAME]
            except KeyError:
                return None
            csrf_token = _sanitize_token(cookie_token)
            if csrf_token != cookie_token:
                # Cookie token needed to be replaced;
                # the cookie needs to be reset.
                request.csrf_cookie_needs_reset = True
            return csrf_token
    def _set_token(self, request, response):
        if settings.CSRF_USE_SESSIONS:
            request.session[CSRF_SESSION_KEY] = request.META['CSRF_COOKIE']
        else:
            response.set_cookie(
                settings.CSRF_COOKIE_NAME,
                request.META['CSRF_COOKIE'],
                max_age=settings.CSRF_COOKIE_AGE,
                domain=settings.CSRF_COOKIE_DOMAIN,
                path=settings.CSRF_COOKIE_PATH,
                secure=settings.CSRF_COOKIE_SECURE,
                httponly=settings.CSRF_COOKIE_HTTPONLY,
            )
            patch_vary_headers(response, ('Cookie',))
    def process_request(self, request):
        csrf_token = self._get_token(request)
        if csrf_token is not None:
            # Use same token next time.
            request.META['CSRF_COOKIE'] = csrf_token
    def process_view(self, request, callback, callback_args, callback_kwargs):
        if getattr(request, 'csrf_processing_done', False):
            return None
        if getattr(callback, 'csrf_exempt', False):
            return None
        if request.method not in ('GET', 'HEAD', 'OPTIONS', 'TRACE'):
            if getattr(request, '_dont_enforce_csrf_checks', False):
                return self._accept(request)
            if request.is_secure():
                referer = force_text(
                    request.META.get('HTTP_REFERER'),
                    strings_only=True,
                    errors='replace'
                )
                if referer is None:
                    return self._reject(request, REASON_NO_REFERER)
                referer = urlparse(referer)
                if '' in (referer.scheme, referer.netloc):
                    return self._reject(request, REASON_MALFORMED_REFERER)
                if referer.scheme != 'https':
                    return self._reject(request, REASON_INSECURE_REFERER)
                good_referer = (
                    settings.SESSION_COOKIE_DOMAIN
                    if settings.CSRF_USE_SESSIONS
                    else settings.CSRF_COOKIE_DOMAIN
                )
                if good_referer is not None:
                    server_port = request.get_port()
                    if server_port not in ('443', '80'):
                        good_referer = '%s:%s' % (good_referer, server_port)
                else:
                    good_referer = request.get_host()
                good_hosts = list(settings.CSRF_TRUSTED_ORIGINS)
                good_hosts.append(good_referer)
                if not any(is_same_domain(referer.netloc, host) for host in good_hosts):
                    reason = REASON_BAD_REFERER % referer.geturl()
                    return self._reject(request, reason)
            csrf_token = request.META.get('CSRF_COOKIE')
            if csrf_token is None:
                return self._reject(request, REASON_NO_CSRF_COOKIE)
            request_csrf_token = ""
            if request.method == "POST":
                try:
                    request_csrf_token = request.POST.get('csrfmiddlewaretoken', '')
                except IOError:
                    pass
            if request_csrf_token == "":
                request_csrf_token = request.META.get(settings.CSRF_HEADER_NAME, '')
            request_csrf_token = _sanitize_token(request_csrf_token)
            if not _compare_salted_tokens(request_csrf_token, csrf_token):
                return self._reject(request, REASON_BAD_TOKEN)
        return self._accept(request)
    def process_response(self, request, response):
        if not getattr(request, 'csrf_cookie_needs_reset', False):
            if getattr(response, 'csrf_cookie_set', False):
                return response
        if not request.META.get("CSRF_COOKIE_USED", False):
            return response
        self._set_token(request, response)
        response.csrf_cookie_set = True
        return response





猜你喜欢

转载自blog.51cto.com/yishi/2498282