Django中间件

Django中间件

中间件的作用

  1. 浏览器的请求先经过中间件验证之后才可以去对应的路由中找到视图函数
  2. 只要是对网址添加全局的功能,就与中间件有关

自定义中间件

发现:无论在页面的哪一个地方return了HttpResponse, render, redirect这三个对象,下面的内容就不走了,直接从最近的process_response向上发返回给浏览器

django中间件,可以自定义五个方法


# 1. 在django项目中新建任意文件夹与py文件

from django.utils.deprecation import MiddlewareMixin

class MyMiddle(MiddlewareMixin):
    """书写自己的中间件"""

    
# 2. 去settings的中间件配置中注册
MIDDLEWARE = [
    ...,
    '地址.类名',
]

# 书写五个方法
# 方法一 (重要)
def process_request(self, request):
   	当浏览器请求来的之后,会依次在中间件中从上至下的运行每个中间件的process_request方法,没有就跳过
    return 这里写的返回值会直接返回页面,但是也要使用from django.shortcuts import HttpResponse, render, redirect 里的
	还有如果return 是空,就不会返回
这里可以用来拦截违规请求

# 方法二 (重要)
def process_response(self, request, response):
    当一切准备就绪时,要返回浏览器时,会先来到中间件的process_response方法,在各个中间件中从下至上的执行
    return response   这里一定要将response参数返回出去,这是给浏览器的数据

# 方法三(了解)
def process_view(self, request, view_func, view_args, view_kwargs):
    在路由匹配成功,来到视图函数之前触发process_view,
	return 与process_request方法的返回值规则一样
也可以在此处拦截

# 方法四(了解)
def process_exception(self,request,exception):
    当视图函数出现异常出错时会进入process_exception方法
    exception是视图函数中的错误信息
    renturn 当return的是空时,django内部会返回一个集体的错误信息,里面包含了错误信息, 也可以return这些方法from django.shortcuts import HttpResponse, render, redirect  来返回
    
# 方法五(了解)想不到应用场景
 def process_template_response(self, request, response):
	process_template_response:当视图函数执行完毕之后并且返回的对象中含有render方法的情况下才会触发
    例1:def yyy(request):
            print('yyy视图函数')
            obj = HttpResponse('随便')
            def render():
                return HttpResponse('hahaha')
            obj.render = render
            return obj

​ 总结:

  1. 在process_request中返回了,直接从最近的,也就是同一中间件中的process_response中向上面的中间件执行,返回个浏览器
  2. 当所有的中间件的process_request都走过了,在有return这些对象,就所有的process_response都从下至上执行后发给浏览器

总结

跨站请求伪造(csrf——Cross-site request forgery)

简单的身份验证只能保证请求发自某个用户的浏览器,却不能保证请求本身是用户自愿发出的

​ 也就是说可以用假冒网站欺骗用户然后拿着用户输入的数据经过修改后向真实网站发post请求

例子:
就类似于你搭建了一个跟银行一模一样的web页面
用户在你的网站转账的时候输入用户名 密码 对方账户
银行里面的钱确实少了 但是发现收款人变了


最简单的原理
form表单中 用户的用户名  密码都会真实的提交给银行后台
但是收款人的账户却不是用户填的 用户输入的是一个没有name属性的input框    而是在form表单中有一个隐藏的带有ame和value的input框

解决方案:打开settings中间件的csrf——为全局视图函数添加csrf校验

​ 利用django的csrf中间件——在form中自动添加了一个隐藏的带有校验随机字符串的input框,然后拿这个字符串匹配比较,从而实现认证

django中是默认开启csrf中间件的

使用form的post如果不携带解决方案中的校验信息是无法通过csrf的校验的

使用csrf核对校验的方式

方式一 form表单直接提交

<form action="" method="post">
    
    {#  在form表单中写csrf_token 就会自动生成校验  #}
    {% csrf_token %}
    <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>
<button id="b1">发ajax</button>

方式二 ajax提交

<form action="" method="post">

    <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>
<button id="b1">发ajax</button>

<script>
    $('#b1').click(function () {
        $.ajax({
            url:"",
            type:"post",
            // 第一种方式
            data:{'username':'jason', 'csrfmiddlewaretoken':$('[name="csrfmiddlewaretoken"]').val()},
            // 第二种方式
            data:{'username':'jason','csrfmiddlewaretoken':'{{ csrf_token }}'},
            data:{'username':'jason'},
            success:function (data) {
                alert(data)
            }
        })
    })
</script>

方式三 导入已经写好的js文件

// 为form表单
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');


// 为ajax
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/或在全局下解除某视图函数的csrf校验

导入

# 必导
from django.views.decorators.csrf import csrf_exempt, csrf_protect

# 为CBV添加要使用
from django.utils.decorators import method_decorator

添加:

1.为FBV添加csrf

@csrf_protect
def pro(request):
    xxxss
    return HttpResponse('pro')

2.为CBV添加csrf

总结:只要为CBV添加装饰器都要使用method_decorator(唯一例外解除csrf——csrf_exempt),并都有四种方式

​ 第一个参数是装饰器名

​ 还有一个参数name:给类添加装饰器时要指定类中具体的方法,方法是dispatch意味着为CBV中每个请求函数都添加了

from django.views import View

# 方式(四)
@method_decorator(csrf_protect,name='dispatch')
# 方式一
@method_decorator(csrf_protect,name='post')
class MyCsrf(View):
    
    # 方式二
    @method_decorator(csrf_protect)
    def dispatch(self, request, *args, **kwargs):
        return super().dispatch(request, *args, **kwargs)
    
    def get(self,request):
        return HttpResponse('hahaha')
    
	# 方式三
    @method_decorator(csrf_protect)
    def post(self,request):
        return HttpResponse('post')

在全局下解除视图函数的csrf校验

1.为FBV解除csrf

@csrf_exempt
def pro(request):
    xxxss
    return HttpResponse('pro')

2.为CBV解除csrf

总结:不同的是只能给dispatch函数装饰,就是解除了CBV中所有请求函数的csrf

from django.views import View

# 方式一
@method_decorator(csrf_exempt,name='dispatch')
class MyCsrf(View):
    
    # 方式二
    @method_decorator(csrf_exempt)
    def dispatch(self, request, *args, **kwargs):
        return super().dispatch(request, *args, **kwargs)
    
    def get(self,request):
        return HttpResponse('hahaha')

    def post(self,request):
        return HttpResponse('post')

posted @ 2019-10-30 20:44  ~李  阅读(124)  评论(0编辑  收藏  举报