[Django高级之中间件、csrf跨站请求伪造]

[Django高级之中间件、csrf跨站请求伪造]

什么是中间件?

Middleware is a framework of hooks into Django’s request/response processing.
It’s a light, low-level “plugin” system for globally altering Django’s input or output.
——————————————————————————-
中间件是一个钩子到Django请求/响应处理的框架。
它是一个轻量级、低级的“插件”系统,用于全局改变Django的输入或输出。

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

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

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

中间件介绍和常用内置中间件

中间件:数据库中间件(mycat,分库分表),

    服务器中间件(tomcat,nginx),

    消息队列中间件(rabbitmq)

    django中间件(Middleware):介于request与response处理之间的一道处理过程,在全局上改变django的输入与输出

django 内置中间件

打开Django项目的Settings.py文件,看到下图的MIDDLEWARE配置项

MIDDLEWARE = [

&#39;django.middleware.security.SecurityMiddleware&#39;, # 安全中间件<br/>
&#39;django.contrib.sessions.middleware.SessionMiddleware&#39;, # 会话中间件:处理session<br/>
&#39;django.middleware.common.CommonMiddleware&#39;,  # 站点中间件:处理是否带斜杠的<br/>
&#39;django.middleware.csrf.CsrfViewMiddleware&#39;,  # CSRF保护中间件:跨站请求伪造的处理<br/>
&#39;django.contrib.auth.middleware.AuthenticationMiddleware&#39;, # 认证中间件:提供用户认证服务<br/>
&#39;django.contrib.messages.middleware.MessageMiddleware&#39;,# 消息中间件:基于cookie或者会话的消息功能<br/>
&#39;django.middleware.clickjacking.XFrameOptionsMiddleware&#39;, # X-Frame-Options中间件:点击劫持保护<br/>

]

SessionMiddleware源码

django.contrib.sessions.middleware.SessionMiddleware
process_request(self, request) # 请求来了会触发
process_response(self, request, response) # 请求走了会触发

  MIDDLEWARE配置项是一个列表(列表是有序的),列表中是一个个字符串,这些字符串其实是一个个类,也就是一个个中间件。

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

Django默认有七个中间件,但是django暴露给用户可以自定义中间件并且里面可以写五种方法

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

process_request(self,request)<br/>
process_response(self, request, response)

2.了解即可

process_view(self, request, view_func, view_args, view_kwargs)<br/>
process_template_response(self,request,response)<br/>
process_exception(self, request, exception)<br/>

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

自定义中间件需要在Django配置文件中告诉Django去哪找这个自定义的中间件,默认可以放在项目的对应app中,新建一个任意名称的文件夹eg:middleware,在此文件夹中新建任意名称的文件eg:my_middleware.py,然后在此文件中根据需求自定义五个方法中的任意一个或多个  

ps:中间件的本质就是含有五个可以修改的内置方法的类,所以自定义的时候需要做的就是先继承一个Django提供的中间件混合的父类(MiddlewareMixin)。

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

注意:自定义中间件必须在settings.py的MIDDLEWARE配置项中注册后才能使用

MIDDLEWARE = [

&#39;django.middleware.security.SecurityMiddleware&#39;,<br/>
&#39;django.contrib.sessions.middleware.SessionMiddleware&#39;,<br/>
&#39;django.middleware.common.CommonMiddleware&#39;,<br/>
&#39;django.middleware.csrf.CsrfViewMiddleware&#39;,<br/>
&#39;django.contrib.auth.middleware.AuthenticationMiddleware&#39;,<br/>
&#39;django.contrib.messages.middleware.MessageMiddleware&#39;,<br/>
&#39;django.middleware.clickjacking.XFrameOptionsMiddleware&#39;,<br/>
&#39;app01.middleware.MyMiddleWare&#39;,  # 自定义中间件<br/>
&#39;app01.middleware.MyMiddleWare1&#39;,  # 自定义中间件

]

process_request方法:(重点)

1.请求来的时候需要经过每一个中间件里面的 process_request方法,经过的顺序是按照配置文件中注册的中间件从上往下的顺序依次执行

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

3.它的返回值可以是None,按正常流程继续走,交给下一个中间件处理,如果该方法返回了Httpresponse对象,那么请求将不再继续往后执行,而是直接原路返回(校验失败不允许访问.)

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

1 请求来了触发它,从上往下依次执行(在setting中中间件注册的位置)

def process_request(self, request):<br/>
如果返回None,就继续往下走<br/>
如果返回四件套之一,直接就回去了

2 在这里面写请求来了的一些判断
3 request.META.REMOTE_ADDR # 客户端地址
4 request.META.HTTP_USER_AGENT # 客户端类型

#自定义中间件示例
from django.utils.deprecation import MiddlewareMixin class MyMiddleWare(MiddlewareMixin):

def process_request(self, request):<br/>
    print(&#39;请求来了0000&#39;)

class MyMiddleWare1(MiddlewareMixin):

def process_request(self, request):<br/>
    print(&#39;请求来了1111&#39;)<br/>

process_response方法:(重点)

1.响应走的时候需要经过每一个中间件里面的 process_response方法,该方法有两个额外的参数 request, response

2,该方法必须返回一个 HttpResponse对象

  1. 默认返回的就是形参 response
  2. 你也可以自己返回自己的

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

# 导入MiddlewareMixin模块
from django.utils.deprecation import MiddlewareMixin
from django.shortcuts import render, HttpResponse,redirect

定义中间件的类,它继承MiddlewareMixin

class MyMiddleWare(MiddlewareMixin):

def process_request(self, request):<br/>
    print(&#39;请求来了0000&#39;)<br/>
    # return HttpResponse(&#39;不让你来了&#39;)

def process_response(self, request, response):

    print(&#39;请求走了0000&#39;)

return response # 一定要return response

定义中间件的类,它继承MiddlewareMixin

class MyMiddleWare1(MiddlewareMixin):

def process_request(self, request):<br/>
    print(&#39;请求来了1111&#39;)

def process_response(self, request, response):

    print(&#39;请求走了1111&#39;)<br/>
    return response<br/>

总结:

当前端发来请求,Django会执行每个中间件中的process_request,执行顺序按照配置文件由上至下执行。

响应走的时候,Django会执行每个中间件中的 process_response方法,process_response方法是在视图函数之后执行的,执行顺序是按照配置文件中注册了的中间件从下往上依次执行

process_view、process_exception、process_template_response(了解):

process_view

路由匹配成功之后执行视图函数之前自动触发<br/>
self,request,view_name,*args,**kwargs

process_exception

当视图函数报错之后自动执行<br/>
self,request,exception

process_template_response

self,request,response<br/>
图函数返回的对象有一个render()方法(或者表明该对象是一个TemplateResponse对象或等价方法)<br/>

详情参考 ← 点击查看

django中处理csrf

1 中间件不要注释了
2 如果是form表单
&lt;form action=“” method=“post”&gt;

# 表单中直接书写下列的语句即可<br/>
{% csrf_token %}

&lt;p&gt;给谁转:&lt;input type=“text” name=“to_user” id=“id_name”&gt;&lt;/p&gt;

&lt;p&gt;转多少:&lt;input type=&#34;text&#34; name=&#34;money&#34; id=&#34;id_money&#34;&gt;&lt;/p&gt;<br/>
&lt;input type=&#34;submit&#34; value=&#34;转账&#34;&gt;

&lt;/form&gt; 3 如果是ajax提交:两种方案

   $.ajax({<br/>
        url: &#39;/transfer/&#39;,<br/>
        method: &#39;post&#39;,<br/>
        //data: {to_user: $(&#39;#id_name&#39;).val(), money: $(&#39;#id_money&#39;).val(),csrfmiddlewaretoken:$(&#39;[name=&#34;csrfmiddlewaretoken&#34;]&#39;).val()},<br/>
       # 方式1:借助于{% csrf_token %}生成的标签(不推荐)

data: {to_user: \((&#39;#id_name&#39;).val(), money: \)(‘#id_money’).val(),csrfmiddlewaretoken:‘{{csrf_token}}’},

       #  方式2:借助于模板语法直接获取<br/>
        success: function (data) {<br/>
            console.log(data)

}

    })

————————————————————

# 方式3:借助于官方提供的js文件自动获取<br/>
# js文件导入即可  代码如下:    直接复制即可!<br/>
# 放于static文件夹下的js文件  之后导入使用即可

function getCookie(name) {

var cookieValue = null;<br/>
if (document.cookie &amp;&amp; document.cookie !== &#39;&#39;) {<br/>
    var cookies = document.cookie.split(&#39;;&#39;);<br/>
    for (var i = 0; i &lt; cookies.length; i++) {<br/>
        var cookie = jQuery.trim(cookies[i]);<br/>
        // Does this cookie string begin with the name we want?<br/>
        if (cookie.substring(0, name.length + 1) === (name + &#39;=&#39;)) {<br/>
            cookieValue = decodeURIComponent(cookie.substring(name.length + 1));<br/>
            break;<br/>
        }<br/>
    }<br/>
}<br/>
return cookieValue;<br/>

}
var csrftoken = getCookie(‘csrftoken’); function csrfSafeMethod(method) {
// these HTTP methods do not require CSRF protection
return (/^(GET|HEAD|OPTIONS|TRACE)\(/.test(method));<br/> } \).ajaxSetup({
beforeSend: function (xhr, settings) {

if (!csrfSafeMethod(settings.type) &amp;&amp; !this.crossDomain) {<br/>
  xhr.setRequestHeader(&#34;X-CSRFToken&#34;, csrftoken);<br/>
}<br/>

}
});

csrf相关装饰器

csrf_exempt 局部不校验csrf

csrf_protect 局部校验csrf

from django.views.decorators.csrf import csrf_exempt, csrf_protect

csrf_exempt 局部不校验csrf

csrf_protect 局部校验csrf

@csrf_protect

@csrf_exempt

def index(request):

if request.method == &#39;POST&#39;:<br/>
    username = request.POST.get(&#39;username&#39;)<br/>
    money = request.POST.get(&#39;money&#39;)<br/>
    target_user = request.POST.get(&#39;target_user&#39;)<br/>
    print(&#39;%s 给 %s 转了 %s 元钱&#39;%(username,target_user,money))<br/>
return render(request,&#39;index.html&#39;)

from django.utils.decorators import method_decorator from django import views

@method_decorator(csrf_protect,name=‘post’) # 第二种 行

@method_decorator(csrf_exempt,name=‘post’) # 第二种 不行

class MyLogin(views.View):

# @method_decorator(csrf_protect)  # 第三种 所有的方法都会加上该功能<br/>
@method_decorator(csrf_exempt)  # 第三种 所有的方法都会加上该功能<br/>
def dispatch(self, request, *args, **kwargs):<br/>
    return super().dispatch(request,*args,**kwargs)

def get(self,request):

    return HttpResponse(&#39;from get&#39;)

@method_decorator(csrf_protect) # 第一种 行

# @method_decorator(csrf_exempt)  # 第一种  不行<br/>
def post(self,request):<br/>
    return HttpResponse(&#39;from post&#39;)

“”“
csrf_exempt该装饰器在CBV中只能给dispatch装才能生效
”“”