郑统京 发表于 2022-11-5 01:25:12

Python深入了解中间件及插拔式思想

# django中间件前戏
django中间件是django的门户
    1、请求来的时候需经过中间件才能到达真正的django后端
    2、相应走的时候也需要中间件发送出去
django自带7个中间件
[画django请求生命周期流程图]
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',
]
class SessionMiddleware(MiddlewareMixin):
    def process_request(self, request):
      session_key = request.COOKIES.get(settings.SESSION_COOKIE_NAME)
      request.session = self.SessionStore(session_key)
    def process_response(self, request, response):
      return response

class CsrfViewMiddleware(MiddlewareMixin):
    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):
      return self._accept(request)
    def process_response(self, request, response):
      return response

class AuthenticationMiddleware(MiddlewareMixin):
    def process_request(self, request):
      request.user = SimpleLazyObject(lambda: get_user(request))
# 我们会发现这些中间件都有一些共同方法支持程序员自定义中间件并且暴露了5个可以自定义的方法]
1、必须掌握
    process_request
    process_response
2、了解即可
    process_view
    process_template_response
    process_exception
def process_request(self, request):def process_response(self, request, response):def process_view(self, request, callback, callback_args, callback_kwargs):def process_template_response(self,request,response):def process_exception(self,request,exception):
# 接下来我们可以根据这些公共方法自己可以自定义中间件# 如何自定义中间件
1、在项目名或者应用名下创建一个任意名称的文件夹
2、在该文件夹内创建一个任意名称的py文件
3、在该py文件需要书写类(必须继承MiddlewareMixin)
    然后在这个类里面就可以自定义五个方法了
    (这个5个方法不是全部都书写的,用几个写几个)
4、需要将类的路径以字符串的形式注册到配置文件中才能生效
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',
    '自己写的中间件1',
    '自己写的中间件2',


from django.utils.deprecation import MiddlewareMixin
from django.shortcuts import render,HttpResponse


class MyMiddleware1(MiddlewareMixin):
    def process_request(self,request):# 只要处理请求的都需要带一个request的形参
      print('我是第一个自定义中间件的process_request方法')

    def process_response(self,request,response):
      print('我是第一个自定义中间件的process_response方法')
      return response

    def process_view(self,request,view_name,*args,**kwargs):
      print(view_name,args,kwargs)
      print('我是第一个自定义中间件里面的process_view')

    def process_template_response(self,request,response):
      print('我是第一个自定义中间件里的process_template_response')
      return response

    def process_exception(self,request,exception):
      print('我是中间件里面的process_exception')
      print(exception)
class MyMiddleware2(MiddlewareMixin):
    def process_request(self,request):# 只要处理请求的都需要带一个request的形参
      print('我是第二个自定义中间件的process_request方法')

    def process_response(self,request,response):
      print('我是第二个自定义中间件的process_response方法')
      return response

    def process_view(self,request,view_name,*args,**kwargs):
      print(view_name,args,kwargs)
      print('我是第er 个自定义中间件里面的process_view')

    def process_template_response(self,request,response):
      print('我是第一个自定义中间件里的process_template_response')
      return response

    def process_exception(self,request,exception):
      print('我是中间件里面的process_exception')
      print(exception)
# 开始刨析必会的request和response的方法1、必须掌握
    [可以用来进行全局的全局的校验,是否为黑名单,数据是否合法-还可以书写一些防爬措施
    :针对请求来的时候执行,上从而下
      1、请求来的时候需要经过每一个经过中间件的process_request方法
      经过的顺寻是按照配置文件中注册中间件从上往下顺序一次执行
      2、如果中间件里面没有定义该方法,那么直接跳过执行下一个
      3、如果该方法返回了HttpResponse对象,那么请求将不再继续往后执行
      而是直接原路返回(校验失败不允许访问...)
      方法就是用来做全局相关的所有限制功能]
-
    -
    [只要用来返回后端传来的HttpResponse对象]
          1、响应走的时候需要经过每一个中间件里面的process_response方法
          该方法有两个参数,request,response
          2、该方法必须返回HttpResponse对象
            1、默认返回的就是形参response(可以实现狸猫换太子自己传回的其他HttpResponse结果)
            2、你也可以自己返回自己的,后买你拿到的所有的都是你设定的了,就不是后端的了
          3、顺序按照配置文件的注册的中间件从下到上,如果没有定义,跳过到下一个

[研究如果在第一个process_request方法就已经返回HttpResponse对象]
那么在响应走的时候是经过所有的中间件 process_response还是有其他情况?
    就是会直接走[同级别的process_response返回,下面直接拦截了

框架也有一个中间件但是他的规律]
    只要返回数据了就必须经过所有的中间件类似于process_response方法
# 了解的是知识点
-
    [路由匹配成功之后,视图函数之前,会自动执行中间件里面的该方法]
    经过的顺序还是按照配置文件中注册中间件从上往下顺序一次执行
-比较难触发,一般不用
    [返回的有HttpResponse对象有render属性时候时候触发]
    顺序是按照配置文件的注册的中间件从下到上

    当视图函数出现了异常的情况下触发
    顺序是按照配置文件中注册了的中间件顺序从下到上
# 钓鱼网站与csrf的由来# csrf 跨站请求伪造
钓鱼网站
    我搭建一个跟正规网站一模一样的界面(中国银行)
    用户不小心进入到了我们的网站,用户给某人打钱
    打钱的操作确确实实提交给中国银行的系统,用户的钱少了
    但是唯一不同的是打钱的账户不是客户想转的账户

大学英语四六级
    考之前需要登录缴费

内部本质
    内部的input的框没有name和value属性,自己手动加了一个input框然后在input框添加
    name='target'和value='jason'属性在用hidden隐藏起来,然后提交post请求得到name和value所对应的值进行操作

如何规避上述的问题
    csrf跨站请求伪造验证
      当网站给用户端返回一个具有提交数据功能页面的时候会给这个页面加一个唯一标识
      当这个页面朝后端发送post请求的时候 我的后端会先校验唯一标识,如果唯一标识不对直接拒绝
      (403 forbidden)如果成功则正常执行
# csrf如何安全实现form表单和Aajx请求的校验请求# 如何符合验证
表单post方法如何引用=
[{% csrf_token %}]
<form action=""method="post">
    {% csrf_token %}
    <p>用户名:<input type="text" name="username"></p>
    <p>target_user:<input type="text" name="target_user"></p>
    <p>money:<input type="text" name="money"></p>
    <input type="submit">
</form>

发送post请求如何引用]
?[第三种通用方法步骤]
1、现在静态文件配置STATICFILES_DIRS =
2、{% load static %}
<script src="{% static 'js/mysetup.js' %}"></script>

<button id="d1">ajax请求</button>
{% load static %}
<script src="{% static 'js/mysetup.js' %}"></script>
<script>
    $('#d1').click(function (){
      $.ajax({
            url:'',
            type:'post',
            // [第一种 利用标签查找获取也买你上的随机字符串]
            {#data:{"username":"jason","csrfmiddlewaretoken":$('').val()}#}
            // [第二种 利用模板语法提供的快捷书写]
            {#data:{"username":"jason","csrfmiddlewaretoken":'{{ csrf_token }}'},#}
            // 第三种 通用方式 直接拷贝js代码并应用到自己的html页面上即可
            data:{"username":"jason"},
            success:function (){

            }
      })
    })
</script>

[本地代码static/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);
            // 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);
    }
}
});
# 如何实现只给部分CBV和FBV添加中间键的csrf需求# csrf相关修饰器
、网站整体不校验csrf,就单单几个视图函数需要校验]

、网站整体都不校验,就单单九个视图函数校验]

"""
-需要校验
    针对csrf_protect符合我们所学的CBV三种玩法]
-豁免/不校验
不需要校验
    针对csrf_exempt只能给dispatch方法加才有效]
"""

# @csrf_exempt
# @csrf_protect
# FBV使用和CBV都可以

def transfer(request):
    if request.method =='POST':
      username = request.POST.get('username')
      target_user = request.POST.get('target_user')
      money = request.POST.get('money')
      print('%s给%s转了%s元'%(username,target_user,money))
    return render(request,'transfer.html')
from django.utils.decorators import method_decorator
from django.views import View

# CBV使用(csrf_protect都可以通用)(但是csrf_exempt只有dispatch可以)
from django.views import View
@method_decorator(csrf_protect,name='post')# [针对第二种方法可以]
class MyCsrfToken(View):
    def dispatch(self, request, *args, **kwargs): # [第三种也可以]
      return super(MyCsrfToken,self).dispatch(request,*args,**kwargs)
    def get(self,request):
      return HttpResponse('get')
    # @method_decorator(csrf_protect) # [针对第一种方法可以]
    def post(self,request):
      return HttpResponse('post')
# 补充拓展知识点,插拔式思想
[重要代码]
import importlib
res = 'myfile.b'
ret =
print(ret)# <module'b'...>模块对象 等价于
==
# 后续补充完善的插拔式请求,之前也更新过,但是感觉思路不清晰,明天我再整理更新一下
def send_all(content):
    for path_str in settings.NOTIFY_LIST:
      module_path,class_name=path_str.rsplit('.',maxsplit=1)
      # module_path = 'notify.email'class_name='Email'
      # 1、利用字符串导入模块
      module= importlib.import_module(module_path) # from notify import email
      # 2、利用反射得到属性名
      cls=getattr(module,class_name) # 通过email得到Email的属性,所以得到了类名
      # 3、生成对象
      obj=cls()
      # 4、利用鸭子类型调用send方法
      obj.send(content)


页: [1]
查看完整版本: Python深入了解中间件及插拔式思想