django中间件

中间件介绍

什么是中间件?

官方的说法:中间件是一个用来处理Django的请求和响应的框架级别的钩子。它是一个轻量、低级别的插件系统,用于在全局范围内改变Django的输入和输出。每个中间件组件都负责做一些特定的功能。

但是由于其影响的是全局,所以需要谨慎使用,使用不当会影响性能。

说的直白一点中间件是帮助我们在视图函数执行之前和执行之后都可以做一些额外的操作,它本质上就是一个自定义类,类中定义了几个方法,Django框架会在请求的特定的时间去执行这些方法。

我们一直都在使用中间件,只是没有注意到而已,打开Django项目的Settings.py文件,看到下图的MIDDLEWARE配置项。

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',
]

MIDDLEWARE配置项是一个列表(列表是有序的,记住这一点,后面你就知道为什么要强调有序二字),列表中是一个个字符串,这些字符串其实是一个个类,也就是一个个中间件。

我们之前已经接触过一个csrf相关的中间件了?我们一开始让大家把他注释掉,再提交post请求的时候,就不会被forbidden了,后来学会使用csrf_token之后就不再注释这个中间件了。

那接下来就学习中间件中的方法以及这些方法什么时候被执行。

自定义中间件

中间件可以定义五个方法,分别是:(主要的是process_request和process_response)

  • process_request(self,request)
  • process_response(self, request, response)
  • process_view(self, request, view_func, view_args, view_kwargs)
  • process_template_response(self,request,response)
  • process_exception(self, request, exception)

以上方法的返回值可以是None或一个HttpResponse对象,如果是None,则继续按照django定义的规则向后继续执行,如果是HttpResponse对象,则直接将该对象返回给用户。

准备工作

  • 在项目名或者应用名下创建一个任意名称的文件夹(应用名下更加解耦合)
  • 在该文件夹内创建一个任意名称的py文件
  • 在该py文件内需要书写类(这个类必须继承MiddlewareMixin)
  • 上面继承的类需要导入模块from django.utils.deprecation import MiddlewareMixin
  • 然后在这个类里就可以自定义5个方法了(用几个写几个)
  • 需要将类的路径以字符串的形式注册到配置文件中才能生效
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',
'你自己写的中间件的路径3',
]

process_request(掌握)

from django.utils.deprecation import MiddlewareMixin

class MyMiddle1(MiddlewareMixin):
def process_request(self, request):
print('我是第一个自定义中间件里面的process_request方法') class MyMiddle2(MiddlewareMixin):
def process_request(self, request):
print('我是第二个自定义中间件里面的process_request方法')

在settings.py的MIDDLEWARE配置项中注册上述两个自定义中间件:

MIDDLEWARE = [
...
# 注册自己的中间件(在应用下创建路径有提示,但是在项目下创建就没有提示了)
'app01.middleware.mymiddleware.MyMiddle1',
'app01.middleware.mymiddleware.MyMiddle2',
]

在view.py里定义如下函数

def index(request):
print('我是视图函数index')
return HttpResponse('index')

访问视图函数index,看一下终端的输出:

把settings.py里注册的MyMiddle1和MyMiddle1的位置调换一下,再访问index视图,会发现终端中打印的内容如下:

如果在中间件里返回HttpResponse对象,那么:

class MyMiddle1(MiddlewareMixin):
def process_request(self, request):
print('我是第一个自定义中间件里面的process_request方法')
return HttpResponse('嘿嘿嘿') # 在这返回HttpResponse对象 class MyMiddle2(MiddlewareMixin):
def process_request(self, request):
print('我是第二个自定义中间件里面的process_request方法')

总结

1.请求来的时候需要经过每个中间件里面的process_request方法

结果的顺序是按照配置文件中注册的中间件从上往下的顺序依次执行

2.如果中间件里没有定义该方法,那么直接跳过执行下一个中间件

3.如果该方法返回了HttpResponse对象,那么请求将不再继续往后执行

而是直接原路返回,并把HttpResponse对象返回到浏览器

process_request方法就是用来做全局相关的所有限制功能

process_response(掌握)

class MyMiddle1(MiddlewareMixin):
def process_request(self, request):
print('我是第一个自定义中间件里面的process_request方法') def process_response(self, request, response):
print('我是第一个自定义中间件里面的process_response方法')
return response # 必须返回 不然报错 class MyMiddle2(MiddlewareMixin):
def process_request(self, request):
print('我是第二个自定义中间件里面的process_request方法') def process_response(self, request, response):
print('我是第二个自定义中间件里面的process_response方法')
return response # 必须返回 不然报错

访问视图函数index,看一下终端的输出:

如果在process_response方法里返回HttpResponse对象

class MyMiddle1(MiddlewareMixin):
def process_request(self, request):
print('我是第一个自定义中间件里面的process_request方法') def process_response(self, request, response):
print('我是第一个自定义中间件里面的process_response方法')
return HttpResponse('哈哈') # 在这里改为返回HttpResponse对象 class MyMiddle2(MiddlewareMixin):
def process_request(self, request):
print('我是第二个自定义中间件里面的process_request方法') def process_response(self, request, response):
print('我是第二个自定义中间件里面的process_response方法')
return response

总结

1.响应走的时候需要经过每一个中间件里面的process_response方法

该方法有两个额外的参数request,response

2.该方法必须返回一个HttpResponse对象,默认返回的就是形参response,也可以返回你定义的

3.顺序是按照配置文件中注册的中间件从下往上依次经过,如果你没定义的话,就直接跳过执行下一个

如果在第一个process_request方法就已经返回了HttpResponse对象,那么响应走的时候是经过所有的中间件里面的process_response还是有其他情况

class MyMiddle1(MiddlewareMixin):
def process_request(self, request):
print('我是第一个自定义中间件里面的process_request方法')
return HttpResponse('baby') # 在这返回HttpResponse对象 def process_response(self, request, response):
print('我是第一个自定义中间件里面的process_response方法')
return response class MyMiddle2(MiddlewareMixin):
def process_request(self, request):
print('我是第二个自定义中间件里面的process_request方法') def process_response(self, request, response):
print('我是第二个自定义中间件里面的process_response方法')
return response

总结:

只走返回了HttpResponse对象该方法的同级的process_response方法

然后就直接原路返回

了解

flask框架也有一个中间件但是它的规律
只要返回数据了就必须经过所有中间件里面的类似于process_reponse方法

process_view(了解)

路由匹配成功之后  执行视图函数之前,会自动执行中间件里面的该方法
顺序是按照配置文件中注册的中间件从上往下的顺序依次执行

process_exception

class MyMiddle1(MiddlewareMixin):
def process_request(self, request):
print('我是第一个自定义中间件里面的process_request方法') def process_response(self, request, response):
print('我是第一个自定义中间件里面的process_response方法')
return response def process_exception(self, request, exception):
print('我是第一个自定义中间件里面的process_exception方法')
print(exception) class MyMiddle2(MiddlewareMixin):
def process_request(self, request):
print('我是第二个自定义中间件里面的process_request方法') def process_response(self, request, response):
print('我是第二个自定义中间件里面的process_response方法')
return response def process_exception(self, request, exception):
print('我是第二个自定义中间件里面的process_exception方法')
print(exception)

在view.py中

def index(request):
print('我是视图函数index')
asdasd # 故意写个语法错误
return HttpResponse('index')

process_template_response(极少)

返回的HttpResponse对象有render属性的时候才会触发
顺序是按照配置文件中注册了的中间件从下往上依次经过

csrf跨站请求伪造

"""
钓鱼网站
我搭建一个跟正规网站一模一样的界面(中国银行)
用户不小心进入到了我们的网站,用户给某个人打钱
打钱的操作确确实实是提交给了中国银行的系统,用户的钱也确确实实减少了
但是唯一不同的时候打钱的账户不适用户想要打的账户变成了一个莫名其妙的账户 大学英语四六级
考之前需要学生自己网站登陆缴费 内部本质
我们在钓鱼网站的页面 针对对方账户 只给用户提供一个没有name属性的普通input框
然后我们在内部隐藏一个已经写好name和value的input框 如何规避上述问题
csrf跨站请求伪造校验
网站在给用户返回一个具有提交数据功能页面的时候会给这个页面加一个唯一标识
当这个页面朝后端发送post请求的时候 我的后端会先校验唯一标识,如果唯一标识不对直接拒绝(403 forbbiden)如果成功则正常执行
"""

csrf校验

针对form表单

在form表单内部的任意位置书写{% csrf_token %}

eg:
<form action="" method="post">
{% csrf_token %} # 在这书写这个就可以通过csrf校验,此时你就不用注释掉csrf那行中间件了
<p>username:<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>

即使没有注释掉 django.middleware.csrf.CsrfViewMiddleware 中间件,也可以成功提交form表单的数据

针对Ajax请求

方式一

$('#d1').click(function (){
$.ajax({
url:'',
type:'post',
// 第一种 利用标签查找获取页面上的随机字符串
data:{'username':'jason','csrfmiddlewaretoken':$('[name=csrfmiddlewaretoken]').val()},
success:function (){
}
})
})

方式二

$('#d1').click(function (){
$.ajax({
url:'',
type:'post',
// 第二种 利用模版语法提供的快捷书写
data:{"username":'jason','csrfmiddlewaretoken':'{{ csrf_token }}'},
success:function (){
}
})
})

方式三

新建一个JS文件,把下面代码CV进去,再把它引入你的html文件中

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);
}
}
});

csrf相关装饰器

在FBV上的效果

csrf_exempt(忽视校验)

# 导入模块
from django.views.decorators.csrf import csrf_exempt, csrf_protect @csrf_exempt
def transfer(request):
return render(request, 'transfer.html')

结论: 可以看出中间件不注释掉用这个@csrf_exempt装饰器也可以忽视校验

csrf_protect(强制校验)

# 注释掉 django.middleware.csrf.CsrfViewMiddleware 中间件
# 导入模块
from django.views.decorators.csrf import csrf_exempt, csrf_protect @csrf_csrf_protect
def transfer(request):
return render(request, 'transfer.html')

结论: 可以看出中间件注释掉用这个@csrf_protect装饰器也可以强制校验

在CBV上的效果

csrf_protect(强制校验)

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

结论: 这三种方式加csrf_protect装饰器都可以正常使用

csrf_exempt(忽视校验)

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

结论: 这三种方式只有再把csrf_exempt装饰器加在dispatch方法上才可以正常使用

importlib模块

# 模块:importlib
import importlib
res = 'myfile.b'
ret = importlib.import_module(res) # 等价于from myfile import b
# 该方法最小单位只能到py文件名

基于django中间件学习编程思想

1.创建一个notify文件夹(名字随便) , 在里面创建4个py文件

2.在email、qq、wechat里书写以下代码3

# qq.py文件内
class Qq(object):
def __init__(self):
pass # 这里写该函数其他的准备工作 def send(self, content):
print('qq通知:%s' % content) # wechat.py文件内
class Wechat(object):
def __init__(self):
pass # 这里写该函数其他的准备工作 def send(self, content):
print('微信通知:%s' % content) # email.py文件内
class Email(object):
def __init__(self):
pass # 这里写该函数其他的准备工作 def send(self, content):
print('邮箱通知:%s' % content)

3.创建settings.py

NOTIFY_LIST = [
'notify.email.Email',
'notify.qq.Qq',
'notify.wechat.Wechat',
]

(核心思想, 很重要)4.在notify文件夹里的_ _ init _ _里书写以下代码

import settings
import importlib def send_all(content):
for path_str in settings.NOTIFY_LIST: # 'notify.email.Email'
module_path, class_name = path_str.rsplit('.', maxsplit=1) # 'notify.email' 'Email'
# 利用字符串导入模块
module = importlib.import_module(module_path) # 等价于from notify import email
# 利用反射获得类名(内存地址)
cls = getattr(module, class_name) # cls就是之前定义的类的名字
# 实例化生成对象
obj = cls()
# 利用鸭子类型直接调用send方法
obj.send(content)

最后创建一个start.py文件看效果

import notify

content = '扑街仔'
notify.send_all(content)

这样你就实现了和django中间件中类似的功能,如果不想用哪个功能直接去settings.py里把对应的字符串注释掉就行了

要添加功能只需要新建一个py文件然后书写功能最后注册进settings.py文件里的列表内就行了

eg:

Django中间件、csrf跨站请求、csrf装饰器、基于django中间件学习编程思想的更多相关文章

  1. Django CBV装饰器 中间件 auth模块 CSRF跨站请求

    CBV添加装饰器 给CBV添加装饰器有三种方法,三种方法都需要导入模块: from django.utils.decorators import method_decorator 第一种直接在方法上面 ...

  2. 第三百一十五节,Django框架,CSRF跨站请求伪造

    第三百一十五节,Django框架,CSRF跨站请求伪造  全局CSRF 如果要启用防止CSRF跨站请求伪造,就需要在中间件开启CSRF #中间件 MIDDLEWARE = [ 'django.midd ...

  3. 十三 Django框架,CSRF跨站请求伪造

     全局CSRF 如果要启用防止CSRF跨站请求伪造,就需要在中间件开启CSRF #中间件 MIDDLEWARE = [ 'django.middleware.security.SecurityMidd ...

  4. csrf跨站请求、相关装饰器、auth模块使用

    昨日内容回顾 django操作cookie和session # 作用:就是保存用户信息,保存一系列数据,还可以做缓存 保留一段时间 # session是基于cookie工作的 1. 数据是保存在服务端 ...

  5. csrf跨站请求伪造、csrf相关装饰器、auth认证模块、基于django中间件设计项目功能

    目录 csrf跨站请求网站 什么是csrf跨站请求网站 经典例子-钓鱼网站 模拟 如何避免这种现象(预防) 如何在django中解决这个问题 form表单 ajax csrf相关装饰器 FBV CBV ...

  6. csrf 跨站请求伪造相关以及django的中间件

    django为用户实现防止跨站请求伪造的功能,通过中间件 django.middleware.csrf.CsrfViewMiddleware来完成. 1.django中常用的中间件? - proces ...

  7. python 全栈开发,Day87(ajax登录示例,CSRF跨站请求伪造,Django的中间件,自定义分页)

    一.ajax登录示例 新建项目login_ajax 修改urls.py,增加路径 from app01 import views urlpatterns = [ path('admin/', admi ...

  8. Web框架之Django_09 重要组件(Django中间件、csrf跨站请求伪造)

    摘要 Django中间件 csrf跨站请求伪造 一.Django中间件: 什么是中间件? 官方的说法:中间件是一个用来处理Django的请求和响应的框架级别的钩子.它是一个轻量.低级别的插件系统,用于 ...

  9. Web框架之Django重要组件(Django中间件、csrf跨站请求伪造)

    Web框架之Django_09 重要组件(Django中间件.csrf跨站请求伪造)   摘要 Django中间件 csrf跨站请求伪造 一.Django中间件: 什么是中间件? 官方的说法:中间件是 ...

随机推荐

  1. Linux指令_入门基础

    一.基础指令语法 1.ls指令: 用法1:#ls 含义:列出当前工作目录下的所有文件/文件夹的名称. 用法2:#ls 路径 含义:列出指定路径下的所有文件/文件夹的名称 用法3:#ls 选项 路径 含 ...

  2. .NET Core剪裁器Zack.DotNetTrimmer升级瘦身引擎,并支持剪裁计划的录制和回放

    上周,我发布了对.NET Core程序进行瘦身的开源软件Zack.DotNetTrimmer,与.NET Core内置的剪裁器相比,Zack.DotNetTrimmer不仅对程序的剪裁效果更好,而且还 ...

  3. 如何解决代码中if/else 过多的问题

    前言 if...else 是所有高级编程语言都有的必备功能.但现实中的代码往往存在着过多的 if...else.虽然 if...else 是必须的,但滥用 if...else 会对代码的可读性.可维护 ...

  4. SpringBoot 如何实现异步编程,老鸟们都这么玩的!

    镜像下载.域名解析.时间同步请点击 阿里巴巴开源镜像站 首先我们来看看在Spring中为什么要使用异步编程,它能解决什么问题? 为什么要用异步框架,它解决什么问题? 在SpringBoot的日常开发中 ...

  5. centos 在线安装 docker

    镜像下载.域名解析.时间同步请点击 阿里巴巴开源镜像站 在新主机上首次安装Docker Engine之前,需要设置Docker存储库.之后,您可以从存储库安装和更新Docker. 设置存储库 安装yu ...

  6. Linux中8个有用的touch命令

    在Linux中,每个文件都有时间戳,并且每个文件都存储上次访问时间,上次修改时间,上次改变时间的信息.因此,无论什么时候我们创建新的文件,访问或者修改一个存在的文件,那个文件的时间戳会自动被更改. 在 ...

  7. 放在initramfs的ko会先加载,还是/lib/modules/下面的ko会先加载?

    如果是在switchroot时加载,用的是initramfs,在switchroot后,用的是硬盘上的,有些ko放到initramfs中,但是switchroot前不加载的话,用的还是硬盘上的,关键看 ...

  8. 基于long pull实现简易的消息系统参考

    我们都用过消息中间件,它的作用自不必多说.但对于消费者却一直有一些权衡,就是使用push,还是pull模式的问题,这当然是各有优劣.当然,这并不是本文想讨论的问题.我们想在不使用长连接的情意下,如何实 ...

  9. Docker容器入门介绍

    1.前言 Docker是一种新兴的虚拟化技术,能够一定程度上的代替传统虚拟机.不过,Docker 跟传统的虚拟化方式相比具有众多的优势.Docker: 本意是码头工人,言外之意是集装箱: Java号称 ...

  10. Jinkins流水线脚本使用curl命令调用服务接口,并且使用url传参。

    curl http://xxx.xx.xx.xx:xxxx/jenkins/publish?fileName=${fileName}&tag_name=${tag_name} 如图调用不符合c ...