zoukankan      html  css  js  c++  java
  • 第七章、中间件续写

    第七章、中间件续写

    一、中间件的执行顺序

    测试思路:

    • 在 settings.py 里注册不同中间件,探究默认的执行顺序
    • 在不同中间件的 process_request 和 process_response 等方法中 return HttpResponse 对象会对执行顺序造成什么影响
    • 了解五种方法的触发时机

    自定义中间件

    1. 新建一个文件夹(放在全局或 app 内)
    2. 写一个类继承 MiddlewareMiXin 类
    3. 里面书写需要的(五个方法中的某些)方法
    4. 一定要在 settings.py 里配置中间件注册

    代码

    mymiddleware/mdd.py 自定义中间件

    from django.utils.deprecation import MiddlewareMixin
    from django.shortcuts import HttpResponse
    class MyMdd(MiddlewareMixin):
    def process_request(self, request):
    print('我是第一个中间件里面的process_request方法')
    def process_response(self, request, response):
    print('我是第一个中间件里面的process_response方法')
    return response
    def process_view(self, request, view_func, view_args, view_kwargs):
    print(view_func)
    print(view_args)
    print(view_kwargs)
    print('我是第一个中间件里面的process_view方法')
    def process_exception(self, request, exception):
    print('我是第一个中间件里面的process_exception')
    def process_template_response(self, request, response):
    print('我是第一个中间件里面的process_template_response')
    return response
    class MyMdd1(MiddlewareMixin):
    def process_request(self, request):
    print('我是第二个中间件里面的process_request方法')
    def process_response(self, request, response):
    print('我是第二个中间件里面的process_response方法')
    return response
    def process_view(self, request, view_func, view_args, view_kwargs):
    print(view_func)
    print(view_args)
    print(view_kwargs)
    print('我是第二个中间件里面的process_view方法')
    def process_exception(self, request, exception):
    print('我是第二个中间件里面的process_exception')
    def process_template_response(self, request, response):
    print('我是第二个中间件里面的process_template_response')
    return response
    class MyMdd2(MiddlewareMixin):
    def process_request(self, request):
    print('我是第三个中间件里面的process_request方法')
    def process_response(self, request, response):
    print('我是第三个中间件里面的process_response方法')
    return response
    def process_view(self, request, view_func, view_args, view_kwargs):
    print(view_func)
    print(view_args)
    print(view_kwargs)
    print('我是第三个中间件里面的process_view方法')
    def process_exception(self, request, exception):
    print('我是第三个中间件里面的process_exception')
    def process_template_response(self, request, response):
    print('我是第三个中间件里面的process_template_response')
    return response

    在 settings.py 中的配置

    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',
    'mymiddleware.mdd.MyMdd', # 配置上
    'mymiddleware.mdd.MyMdd1', # 配置上
    'mymiddleware.mdd.MyMdd2', # 配置上
    ]

    我们可以总结一下:

    process_request

    请求来的时候会依次执行 settings.py 配置文件中注册了的中间件里的该方法

    • 如果没有该方法则直接跳过,走下一个中间件
    • 如果该方法里返回了 HttpResponse 对象,那么会直接从当前中间件的 process_response 方法 从下往上依次执行返回,不会再接着往下执行
    • 执行顺序:从上往下
    • 该方法可以实现对用户身份的校验,访问频率的限制,用户权限的校验...

    process_response

    响应走的时候会依次执行 settings.py 配置文件中注册了的中间件里的该方法(必须将 response 形参返回,因为这个 response 指代的就是返回给前端的数据)

    • 如果没有该方法则直接跳过,走下一个中间件
    • 执行顺序:从下往上
    • 该方法可以帮你实现缓存机制(减缓服务器、数据库的压力)

    process_view

    路由匹配成功 执行视图函数之前 自动触发(从上往下依次执行)

    process_exception

    视图函数报错了,自动触发(从下往上依次执行)

    process_template_response

    视图函数返回的 HttpResponse 对象中包含了 render 属性时会触发,或者是表明一个对象时 TemplateResponse 对象或等价方法 的时候也会触发(从下往上依次执行)

    def index(request):
        print("我是 index 视图函数")
        def render():
            return HttpRespone('用户最终能够看到的结果')  # ******
        obj = HttpResponse('index')
        obj.render = render  # 返回的 HttpResponse 对象中必须包含 render 属性,才能触发中间件里定义的 process_template_response 方法
        return obj
    

    强调:在写中间件的时候,只要形参中有 response ,就要记得将其返回,这个Response 是要给前端的信息

    二、跨站请求伪造

    顾名思义:可以做出钓鱼网站这种的
    就类似于你搭建了一个跟银行一模一样的web页面
    用户在你的网站转账的时候输入用户名 密码 对方账户
    银行里面的钱确实少了 但是发现收款人变了

    到底咋回事呢?

    你写的form表单中 用户的用户名  密码都会真实的提交给银行后台
    但是收款人的账户却不是用户填的 你暴露给用户的是一个没有name属性的input框
    你自己提前写好了一个隐藏的带有name和value的input框
    

    解决钓鱼网站的策略

    
        只要是用户想要提交post请求的页面 我在返回给用户的时候就提前设置好一个随机字符串
        当用户提交post请求的时候  我会自动先取查找是否有该随机字符串 
        如果有 正常提交
        如果没有  直接报403 
    

    三、csrf装饰器

    from django.views.decorators.csrf import csrf_exempt,csrf_protect,ensure_csrf_cookie
    
    csrf_exempt   # 某个视图不需要进行csrf校验
    
    csrf_protect  # 某个视图需要进行csrf校验
    
    ensure_csrf_cookie  # 确保生成csrf的cookie
    
    1. csrf_exempt

      只有两种装饰的方式:

      from django.views.decorators.csrf import csrf_exempt, csrf_protect
      from django.utils.decorators import method_decorator
      
      # 第一种
      @method_decorator(csrf_exempt, name='dispatch')
      class MyCsrf(View):
          
          # 第二种
          @method_decorator(csrf_exempt)
          def dispatch(self, request, *args, **kwargs):
              return super().dispatch(request,*args,**kwargs)
          def get(self,request):
              return HttpResponse('hahaha')
      
    2. csrf_protect

      除了csrf_exempt之外,所有的其他装饰器在CBV上面都有三种方式:

      @method_decorator(csrf_protect,name='post')
      class MyCsrf(View):
          @method_decorator(csrf_protect)
          def dispatch(self, request, *args, **kwargs):
              return super().dispatch(request,*args,**kwargs)
          def get(self,request):
              return HttpResponse('hahaha')
      
          @method_decorator(csrf_protect)
          def post(self,request):
              return HttpResponse('post')
      
    3. 这个是我的知识盲区 后续再补

    四、post请求提交数据通过 csrf 校验

    目前所学的拥有post请求的方法有form表单和ajax发送

    form表单

    你在写的时候只需要加上一个
                {% csrf_token %}
    

    ajax发送有三种

    第一种  自己再页面上先通过{% csrf_token %}获取到随机字符串  然后利用标签查找 
    data:{'username':'jason','csrfmiddlewaretoken':$('[name="csrfmiddlewaretoken"]').val()},
    第二种
    data:{'username':'jason','csrfmiddlewaretoken':'{{ csrf_token }}'},
    第三种
    sataic文件夹 再创建一个js文件 拷贝代码
    

    下面给出第三种的js代码

    function getCookie(name) {
        var cookieValue = null;
        if (document.cookie && document.cookie !== '') {
            var cookies = document.cookie.split(';');
            for (var i = 0; i < cookies.length; i++) {
                var cookie = jQuery.trim(cookies[i]);
                // Does this cookie string begin with the name we want?
                if (cookie.substring(0, name.length + 1) === (name + '=')) {
                    cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
                    break;
                }
            }
        }
        return cookieValue;
    }
    var csrftoken = getCookie('csrftoken');
    
    
    
    function csrfSafeMethod(method) {
      // these HTTP methods do not require CSRF protection
      return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
    }
    
    $.ajaxSetup({
      beforeSend: function (xhr, settings) {
        if (!csrfSafeMethod(settings.type) && !this.crossDomain) {
          xhr.setRequestHeader("X-CSRFToken", csrftoken);
        }
      }
    });
    

    然后在html文件上加这一行就好了

    {#<script src="/static/setup.js"></script>#}
    

    这样就不需要 在 html 中写 {% csrf_token %} 或在 ajax 中写 {{ csrf_token }}

    五、自我拷问

    • 当你网站全局都需要校验 csrf 的时候(未注释掉 csrf 中间件时),有几个不需要校验该如何处理? @csrf_exempt

    • 当你的网站全局不校验 csrf 的时候(注释掉 csrf 中间件时),有几个需要校验该如何处理 ?@csrf_protect

    分FBV和CBV

    未注释掉 csrf 中间件时 单功能取消 csrf 校验:csrf_exempt

    FBV怎么写?

    from django.views.decorators.csrf import csrf_exempt
    
    # 全局开启时,局部禁用
    @csrf_exempt
    def index(request):
      pass
    

    CBV怎么写?

    有两种方式,不能针对单个方法,是针对全局的

    # CBV比较特殊,不能单独加在某个方法上
    # 只能加在类上或dispatch方法上
    from django.utils.decorators import method_decorator
    from django.views.decorators.csrf import csrf_exempt
    
    
    # @method_decorator(csrf_exempt,name='dispatch')  # 第一种
    class Csrf_Token(View):
        @method_decorator(csrf_exempt)  # 第二种
        def dispatch(self,request,*args,**kwargs):
            res = super().dispatch(request,*args,**kwargs)
            return res
          # @method_decorator(csrf_exempt)  # 这里这么写不行!!!
        def get(self,request):
                pass
        def post(self,request):
                pass
    

    注释掉 csrf 中间件时 单功能开启 csrf 校验:csrf_protect

    FBV怎么写?

    from django.views.decorators.csrf import csrf_protect
    
    
    @csrf_protect
    def lll(request):
        return HttpResponse('lll')
    

    CBV怎么写?

    from django.views.decorators.csrf import csrf_protect
    
    from django.views import View
    from django.utils.decorators import method_decorator
    
    
    # 第一种方式
    # @method_decorator(csrf_protect,name='post')  # 有效的
    class MyView(View):
        @method_decorator(csrf_protect)  # 第三种方式
        def dispatch(self, request, *args, **kwargs):
            res = super().dispatch(request, *args, **kwargs)
            return res
    
        def get(self, request):
            return HttpResponse('get')
    
        # 第二种方式
        # @method_decorator(csrf_protect)  # 有效的
        def post(self, request):
            return HttpResponse('post')
    

    原文借鉴了https://www.cnblogs.com/suwanbin/p/11591887.html

    在这里感谢!

  • 相关阅读:
    如何在Mac下配置多个Java版本
    robotframework-SikuliLibrary 第三方库
    点击按钮,按钮没有悬浮效果,不能拖拽元素。
    robot framework ——关键字run keyword if 如何在一个条件下接多个执行语句
    iOS测试中发现一个textview控制,使用clear()无法清除文字
    AppiumLibrary 关键字文档
    "startIWDP": true
    Proxifier ,CCProxy 新发现的东西。
    第一次Git上传本地项目到github上 的命令
    c#之数组
  • 原文地址:https://www.cnblogs.com/demiao/p/11768709.html
Copyright © 2011-2022 走看看