16. 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中的注册顺序从前往后一次执行)
process_view

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则通过伪装来自受信任用户的请求来利用受信任的网站

攻击原理如下图:

img

从上图可以看出,要完成一次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)
  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值