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. Eureka 基本教程

    目录 Eureka 基本教程 RestTemplate 使用 Eureka 使用 注册中心 提供者 消费者 Eureka 基本教程 RestTemplate 使用 学习Euraka的同学直接滑到最下面 ...

  2. unicode和unicode编码

    unicode编码是什么? 这其实是两个问题,unicode 是什么什么?unicode是怎样编码的? What is Unicode? Unicode provides a unique numbe ...

  3. rancher接管已部署的集群

    1.选择一台服务器部署rancher服务 docker pull rancher/rancher:v2.5.6 #拉取rancher镜像 docker run --privileged -d -v / ...

  4. 【OpenHarmony移植案例与原理】XTS子系统之应用兼容性测试用例开发

    摘要:本文主要介绍ACTS应用兼容性测试用例开发编译. 本文分享自华为云社区<移植案例与原理 - XTS子系统之应用兼容性测试用例开发>,作者: zhushy . XTS(X Test S ...

  5. 嵌入式linux驱动开发 笔记

    @ 目录 首个驱动hellodrv 1.编写源码 2.编译模块 3.加载驱动 首个驱动hellodrv 3.如果下载不到,就自己编写,并编译驱动. 1.编写源码 2.编译模块 1.先写makefile ...

  6. SQL语句优化、mysql不走索引的原因、数据库索引的设计原则

    SQL语句优化 1 企业SQL优化思路 1.把一个大的不使用索引的SQL语句按照功能进行拆分 2.长的SQL语句无法使用索引,能不能变成2条短的SQL语句让它分别使用上索引. 3.对SQL语句功能的拆 ...

  7. 4月26日 python学习总结 JoinableQueue、线程、三种锁

    一.进程队列补充-创建进程队列的另一个类JoinableQueue JoinableQueue同样通过multiprocessing使用. 创建队列的另外一个类: JoinableQueue([max ...

  8. 同一局域网ping ip 失败(可能是你的路由器坑了你)

    事件起源:手机需要通过fiddler代理抓包 一顿操作猛如虎,手机输入ip+端口,芭比q了,连接不上.. 解决思路: 一.保证双方处于同一局域网内 二.查看电脑配置,找到 防火墙,关闭防火墙,再试 三 ...

  9. 在idea中新建完springboot项目的时候遇到问题(右键没有class选择;控制台报错:Could not transfer artifact org.apache.tomcat.embed:tomcat-embed-core:jar:9.0.60 from/to central ....)

    一.在idea中新建完springboot项目的时候遇到问题 问题1:右键没有class选择 解决:之所以会如此,是因为项目还没完成创建完成,解决:只需等等即可,等到完全创建完成即可 问题2(报tom ...

  10. JavaScript01 js基础语法,数据类型

    JavaScript的概述: 1.组成 三部分组成 ecmaScript 基础语法 (es5) dom document object model 文档对象模型 (操作html文档内容) bom bo ...