16. django的中间件
程序员文章站
2022-06-06 10:33:19
...
django中间件
一、中间件简介
1、什么是中间件?
中间件,是介于request与response处理之间的一道处理过程,相对比较轻量级,并且在全局上改变django的输入与输出
由于它影响的是全局,所以需要谨慎使用,用不好会影响到性能
2、作用
如果你想修改请求,例如被传送到view中的HTTPResponse对象,或者你想修改HttpResponse对象,这些都可以通过中间件实现
如果你还想在view执行之前做一些操作,这种情况就可以用middleware来实现
- 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',
]
二、自定义中间件
1、process_request和process_response
当用户发起请求的时候会依次经过所有的的中间件,这个时候的请求是process_request,最后到达views的函数中,views函数处理后,在依次穿过中间件,这个时候是process_response,最后返回给请求者
# 多个中间件的执行顺序:
- 请求来的时候从上往下执行:process_request
- 请求走的时候从下往上执行:process_response
# process_requset的作用:
- 写一个中间件,不管前端使用编码,在request.data中都有post数据
- 频率限制(限制某个ip地址,如限制一分钟内只能访问5次)
- 登录认证(没登录就重定向到login路径)
- 记录用户访问日志(ip,访问时间,访问路径)
# process_response作用——内部有response对象
- 统一给所有的(/某几个)路径加上cookie、响应头
2、自定义中间件步骤
上图中的中间件是django自带的,我们可以自定义一个中间件:
# 自定义步骤:
#1、写一个类,继承MiddlewareMixin
from django.utils.deprecation import MiddlewareMixin
class Md1(MiddlewareMixin):
pass
#2、在类中写process_request(请求来了一定会触发此方法执行)等方法
def process_request(self,request):
pass
def process_response(self,request,response):
pass
#3、在views.py中定义一个视图函数
def index(request):
return HttpResponse('ok')
#4、在settings.py中的MIDDLEWARE中注册自己的中间件
(注意放的位置,比如放在'django.contrib.sessions.middleware.SessionMiddleware'前面如果使用session会报错)
加在settings中的写法示例:
MIDDLEWARE = [
...
'app01.mymiddle.MyMiddleware1',
...
]
三、中间件的几个主要方法
- 中间件的几个主要方法:
- process_request(self,request)
- process_view(self, request, callback, callback_args, callback_kwargs)
- process_template_response(self,request,response)
- process_exception(self, request, exception)
- process_response(self, request, response)
1、process_request(request对象)
from django.utils.deprecation import MiddlewareMixin
class MyMiddle(MiddlewareMixin):
def process_request(self, request):
print('来了个请求')
print(request.session)
# 不要返回 非None的值
# 如果返回HttpResponse对象,就不会进入视图层执行函数,会直接中断request请求
# return HttpResponse('不让访问')
如果在process_request() 直接返回了:
2、process_response(request对象, response对象)
def process_response(self, request, response):
print('请求走了')
return response
# 一定要返回response,否则后面的内置中间件执行时找不到response对象会报错
# response是视图函数返回的HTTPResponse对象,也就是说,这是django后台处理完之后给出的一个具体的视图,
# 该方法的返回值必须是HTTPResponse对象,如果不返回response而返回其他对象,则浏览器拿的就是中间件返回的这个对象,不会拿到django后台给他的视图
- 总结:
#1、中间件的process_request方法是在执行视图函数之前执行的
#2、当配置多个中间件时,会按照MIDDLEAWARE中的注册顺序,也就是列表的索引值,从前到后依次执行
#3、不同中间件之间传递的request都是同一个对象
#4、多个中间件中的process_response方法是按照MIDDLEWARE中的注册顺序倒序执行的,也就是说第一个中间件的process_request方法首先执行,而它的process_response方法最后执行,最后一个中间件的process_request方法最后一个执行,它的process_response方法是最先执行。
3、process_view
# process_view,在路由匹配成功和视图函数执行之前 执行(callback就是视图函数)
def process_view(self, request, callback, callback_args, callback_kwargs):
print(callback) # 视图函数
print(callback_args) # 视图函数的参数
print(callback_kwargs) # 视图函数的参数
# (相当于是个装饰器)视图函数执行之前的代码块...
res = callback(request)
# (相当于是个装饰器)视图函数执行之后的代码块...
return res
# 参数:
- request:是HTTPResponse对象
- callback:是Django即将执行的视图函数(是实际的函数对象,不是函数的名称)
- callback_args:是将传给视图函数callback的位置参数的列表
- callback_kwargs:是将传给视图函数callback的关键字参数的字典
# django会在调用函数之前调用process_view方法
它应该返回None或者HttpResponse对象,
- 如果返回None,django将继续处理这个请求,执行其他中间件的process_view方法,然后再执行相应的视图;
- 如果返回一个HttpResponse对象,django不会调用对应的视图函数,而是直接掉头,倒序执行中间件的process_response方法,最后返回给浏览器
- 执行顺序示意图:(按照MIDDLEWARE中的注册顺序从前往后一次执行)
4、process_exception
# 视图函数出错,会执行它(全局异常捕获),可以记录日志,记录用户ip地址,是访问哪个路径出的错
def process_exception(self, request, exception):
print(exception)
return render(request, 'error.html')
# 它返回的值可以是一个HTTPResponse对象或者None,
- 如果返回HTTPResponse,django将调用模板和中间件中的process_response方法,并返回给浏览器,否则将默认处理异常
- 如果返回None,则交给下一个中间件的process_exception方法来处理异常,他的执行顺序也是按照中间件注册顺序的倒序执行
# 如果视图函数中无异常,process_exception方法不执行
5、process_template_response(用的比较少)
process_template_response(self, request, response)
# 参数:
- request:一个HTTPResponse对象,response是TemplateResponse对象(由视图函数或者中间件产生)
# process_template_response是在视图函数执行完成后立即执行,前提是视图函数必须要返回一个render方法(或者表明该对象是一个TemplateResponse对象或等价方法)
四、CSRF_TOKEN跨站请求伪造
1、 CSRF是什么?
CSRF(Cross-site request forgery)跨站请求伪造,是一种对网站的恶意利用,与XSS不同,XSS利用站点内的信任用户,而CSRF则通过伪装来自受信任用户的请求来利用受信任的网站
攻击原理如下图:
从上图可以看出,要完成一次CSRF攻击,受害者必须依次完成两个步骤:
1.登录受信任网站A,并在本地生成Cookie。
2.在不登出A的情况下,访问危险网站B。
2、django中解决CSRF攻击的方法
# 中间件:django.middleware.csrf.CsrfViewMiddleware
# 每次发送post请求的时候,都需要csrf_token随机字符
- form提交:表单中添加{% csrf_token %}
<form action="" method="post">
{% csrf_token %}
<p>用户名:<input type="text" name="name"></p>
<p>密码:<input type="password" name="password"></p>
<p><input type="submit" value="提交"></p>
</form>
- ajax请求提交
# 方式一:放到data中
$("#id_btn").click(function () {
$.ajax({
url: '/csrf_test/',
method: 'post',
data: {
'name': $('[name="name"]').val(),
'password': $('[name="password"]').val(),
'csrfmiddlewaretoken': $('[name="csrfmiddlewaretoken"]').val(),
},
success: function (data) {
console.log('成功了')
console.log(data)
},
error: function (data) {
console.log('失败了')
console.log(data)
}
})
})
# 方式二:
data: {
'name': $('[name="name"]').val(),
'password': $('[name="password"]').val(),
'csrfmiddlewaretoken':'{{ csrf_token }}',
},
# 方式三:放到请求头里面
headers:{'X-CSRFToken':"{{ csrf_token }}"},
或者
headers:{'X-CSRFToken': $('[name="csrfmiddlewaretoken"]').val()},
# 方式四:取出cookie中csrftoken对应的值,放进headers
3、全局使用,局部禁用csrf
-实现方式:
# 在视图函数上加装饰器
# 触发前提, 'django.middleware.csrf.CsrfViewMiddleware',这个中间件不能被注释
from django.views.decorators.csrf import csrf_exempt
@csrf_exempt
def csrf_test(request):
pass
4、全局禁用,局部使用
# 触发前提:在settings中中间件注册中注释掉'django.middleware.csrf.CsrfViewMiddleware',
from django.views.decorators.csrf import csrf_protect
@csrf_protect
def csrf_test(request):
pass
5、csrf装饰器神奇(古怪)的用法
url配置中:
urlpatterns = [
path('admin/', admin.site.urls)
path('csrf_test/', csrf_exempt(views.csrf_test)),
]
# 原理就是: 既然csrf_exempt是一个装饰器,那么他就可以将后面执行的函数的内存地址(即函数名)放进它的括号中,当做装饰器的实参
五、补充
1、jquery.cookie.js
# jquery.cookie.js
- 可以在浏览器中对cookie进行增删查改
- 前后端分离(js操作cookie)
上一篇: 16.进程间的通信:管道
下一篇: 线性表----循环链表和静态链表