Django中间件、csrf跨站请求、csrf装饰器、基于django中间件学习编程思想
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中间件学习编程思想的更多相关文章
- Django CBV装饰器 中间件 auth模块 CSRF跨站请求
CBV添加装饰器 给CBV添加装饰器有三种方法,三种方法都需要导入模块: from django.utils.decorators import method_decorator 第一种直接在方法上面 ...
- 第三百一十五节,Django框架,CSRF跨站请求伪造
第三百一十五节,Django框架,CSRF跨站请求伪造 全局CSRF 如果要启用防止CSRF跨站请求伪造,就需要在中间件开启CSRF #中间件 MIDDLEWARE = [ 'django.midd ...
- 十三 Django框架,CSRF跨站请求伪造
全局CSRF 如果要启用防止CSRF跨站请求伪造,就需要在中间件开启CSRF #中间件 MIDDLEWARE = [ 'django.middleware.security.SecurityMidd ...
- csrf跨站请求、相关装饰器、auth模块使用
昨日内容回顾 django操作cookie和session # 作用:就是保存用户信息,保存一系列数据,还可以做缓存 保留一段时间 # session是基于cookie工作的 1. 数据是保存在服务端 ...
- csrf跨站请求伪造、csrf相关装饰器、auth认证模块、基于django中间件设计项目功能
目录 csrf跨站请求网站 什么是csrf跨站请求网站 经典例子-钓鱼网站 模拟 如何避免这种现象(预防) 如何在django中解决这个问题 form表单 ajax csrf相关装饰器 FBV CBV ...
- csrf 跨站请求伪造相关以及django的中间件
django为用户实现防止跨站请求伪造的功能,通过中间件 django.middleware.csrf.CsrfViewMiddleware来完成. 1.django中常用的中间件? - proces ...
- python 全栈开发,Day87(ajax登录示例,CSRF跨站请求伪造,Django的中间件,自定义分页)
一.ajax登录示例 新建项目login_ajax 修改urls.py,增加路径 from app01 import views urlpatterns = [ path('admin/', admi ...
- Web框架之Django_09 重要组件(Django中间件、csrf跨站请求伪造)
摘要 Django中间件 csrf跨站请求伪造 一.Django中间件: 什么是中间件? 官方的说法:中间件是一个用来处理Django的请求和响应的框架级别的钩子.它是一个轻量.低级别的插件系统,用于 ...
- Web框架之Django重要组件(Django中间件、csrf跨站请求伪造)
Web框架之Django_09 重要组件(Django中间件.csrf跨站请求伪造) 摘要 Django中间件 csrf跨站请求伪造 一.Django中间件: 什么是中间件? 官方的说法:中间件是 ...
随机推荐
- 手写 Vue2 系列 之 patch —— diff
前言 上一篇文章 手写 Vue2 系列 之 初始渲染 中完成了原始标签.自定义组件.插槽的的初始渲染,当然其中也涉及到 v-bind.v-model.v-on 指令的原理.完成首次渲染之后,接下来就该 ...
- VS2022不能使用<bits/stdc++.h>的解决方案
•<bits/stdc++.h>介绍 #include<bits/stdc++.h> 包含了目前 C++ 所包含的所有头文件,又称万能头文件,简直是开挂一般的存在. 你编程 ...
- Net中事件的高级用法之三
1.事件的高级应用 使用事件可以解除代码耦合 2.事件高级应用实例 using System; using System.Collections.Generic; using System.Linq; ...
- JVM基本概念
JVM基础概念 什么是JVM JVM:Java virtual machine,Java虚拟机,它是一种规范.是虚构出来的一台计算机.它可以将二进制字节码根据不同的操作系统转为当前操作系统识别的的字节 ...
- 6月11日 python学习总结 框架理论
Web框架本质及第一个Django实例 Web框架本质 我们可以这样理解:所有的Web应用本质上就是一个socket服务端,而用户的浏览器就是一个socket客户端. 这样我们就可以自己实现Web ...
- google hacker语法
intext:关键字 搜索网页正文中含有这些关键字的网页. intitle:关键字 搜索网页标题中含有这些关键字的网页. cache:关键字 搜索含有关键字内容的cache. define:关键字 搜 ...
- [转载]Linux后门整理合集(脉搏推荐)
我在思考要不要联系下....都禁止转载了.... 简介 利用 Unix/Linux 自带的 Bash 和 Crond 实现远控功能,保持反弹上线到公网机器. 利用方法 先创建 /etc/xxxx 脚本 ...
- 浅析 c++ bitset 的用法
浅析 c++ bitset 的用法 总述 C++的 \(bitset\) 位于 <bitset> 头文件中,这是一种类似于数组的数据结构,每个位置存储 \(0\ or\ 1\) ,并且每个 ...
- [USACO08OPEN]牛的街区Cow Neighborhoods
题目描述: luogu 题解: 技巧题. 曼哈顿距离:$|x1-x2|+|y1-y2|$ 切比雪夫距离:$\max(|x1-x2|,|y1-y2|)$ 曼哈顿距离转切比雪夫距离:$(x,y)-> ...
- Android BLE 蓝牙开发——扫码枪基于BLESSED
一.蓝牙模式HID与BLE 当扫码枪与手机连接时,通常采用的是蓝牙HID(Human Interface Device)模式.本质上是一个把扫码枪作为一个硬件键盘,按照键盘协议把扫码后的结果逐个输入到 ...