57.1 django中间件 自定义中间件 csrf中间件
1.django 请求生命周期流程图
1.介绍
它是django的门户 只要是全局相关的功能你都应该考虑使用django中间件来帮你完成 全局用户身份校验 全局用户访问频率校验 用户访问黑名单 用户访问白名单 # 只要以后用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', ]
2.django自定义中间件
1.查看源码
from django.middleware.security import SecurityMiddleware class SessionMiddleware(MiddlewareMixin): def process_request(self, request): def process_response(self, request, response): class CsrfViewMiddleware(MiddlewareMixin): def process_request(self, request): def process_view(self, request, callback, callback_args, callback_kwargs): def process_response(self, request, response):
2. django支持用户自定义中间件并且暴露给用户五个可以自定义的方法
1.需要掌握的 process_request(******) 请求来的时候会按照配置文件中注册的中间件从上往下的顺序依次执行每一个中间件里面的process_request方法,如果没有直接跳过执行下一个 同级别返回 并不会全部执行process_response process_response 响应走的时候会按照配置文件中注册的中间件从下往上的顺序依次执行每一个中间件里面的 process_response方法 该方法必须要有两个形参 并且需要将形参response返回 如果你内部自己返回了HttpResponse对象 会将返回给用户浏览器的内容替换成你自己的 2.需要了解的 process_view 路由匹配成功执行视图函数之前触发 process_template_reponse 视图函数返回的对象中必须要有render属性对应的render方法 def index(request): print('我是视图函数index') def render(): return HttpResponse("你好啊 我是index里面的render函数") obj = HttpResponse("index") obj.render = render return obj process_exception 当视图函数报错的时候自动触发 信号量
3.自定义中间件
定义中间件
注册中间件
4. process_reuest 方法
1.请求来的时候 中间件从上到下执行中间中的process_request 方法,然后再执行views函数中的方法
2.一旦prcocess_request 方法中返回了 httpresponse方法,请求就不在往后执行了,而是原路返回
5.process_response 方法
响应走的时候 中间件 从下往上执行process_reponse方法 如果没理解 结合django请求周期流程图去看
如果 process_reponse方法 不返回response,而是httpresponse,则直接返回httpresponse的内容
同级别返回 process_request方法中如果定义了httpresponse返回,
则会直接丢给同级别的process_response方法去处理,然后依次向上返回
代码
from django.utils.deprecation import MiddlewareMixin from django.shortcuts import HttpResponse class Mymd1(MiddlewareMixin): def process_request(self,request): print('我是第一个自定义中间件里面的process_request方法') # return HttpResponse("我是第一个中间件返回的Httpresponse对象") def process_response(self,request,response): print('我是第一个中间件里面的process_reponse方法') return response # 就是后端返回给前端浏览器的响应数据 def process_view(self,request,view_func,*args,**kwargs): print(view_func,args,kwargs) print('我是第一个中间件里面的process_view') def process_template_response(self,request,response): print('我是第一个中间件里面的process_template_reponse方法') return response def process_exception(self,request,exception): print('exception:',exception) print('我是第一个中间件里面的process_exception') class Mymd2(MiddlewareMixin): def process_request(self,request): print('我是第二个自定义中间件里面的process_request方法') def process_response(self, request, response): print('我是第二个中间件里面的process_reponse方法') return response def process_view(self,request,view_func,*args,**kwargs): print(view_func,args,kwargs) print('我是第二个中间件里面的process_view') def process_template_response(self,request,response): print('我是第二个中间件里面的process_template_reponse方法') return response def process_exception(self,request,exception): print('exception:',exception) print('我是第二个中间件里面的process_exception')
6.了解方法 (知道什么时候触发即可)
process_view :在路由匹配成功执行视图函数之前触发 参考jason
process_template_response: 视图函数返回的对象中必须要有render属性对应的render方法
process_exception:当视图函数报错的时候触发
3.跨站请求伪造 csrf中间件
1.引入:
钓鱼网站
钓鱼网站
本质搭建一个跟正常网站一模一样的页面
用户在该页面上完成转账功能
转账的请求确实是朝着正常网站的服务端提交
唯一不同的在于收款账户人不同
给用户书写form表单 对方账户的input没有name属性
你自己悄悄提前写好了一个具有默认的并且是隐藏的具有name属性的input
模拟钓鱼网站
解决办法:前端form表单加入{%csrf_token%}, 打开csrf中间件
2.即form表单post请求通过csrf中间件验证
3.Ajax post请求通过csrf中间件验证的三种方式
ajax如何通过csrf校验 // 第一种方式 自己手动获取 {#data:{'username':'jason','csrfmiddlewaretoken':$('input[name="csrfmiddlewaretoken"]').val()},#} // 第二种方式 利用模板语法 {#data:{'username':'jason','csrfmiddlewaretoken':'{{ csrf_token }}'},#} // 第三种 通用方式 引入外部js文件 官网提供的方式 {% load static %} <script src="{% static 'myset.js' %}"></script> data:{'username':'jason'}
<h2>我是正儿八经的网站</h2> <form action="" method="post"> {# {% 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="d1">发送ajax请求</button> {#{% load static %}#} {#<script src="{% static 'myset.js' %}"></script>#} {#<script>#} {# $('#d1').click(function () {#} {# $.ajax({#} {# url:'',#} {# type:'post',#} {#data:{'username':'jason'},#} {# // 第一种方式 自己手动获取#} {#data:{'username':'jason','csrfmiddlewaretoken':$('input[name="csrfmiddlewaretoken"]').val()},#} {# // 第二种方式 利用模板语法#} {#data:{'username':'jason','csrfmiddlewaretoken':'{{ csrf_token }}'},#} {# // 第三种 通用方式 引入外部js文件#} {# data:{'username':'jason'},#} {# success:function (data) {#} {# alert(data)#} {# }#} {# })#} {# })#} {#</script>#}
第三种方式(引入外部js文件)解释 (不用记cv就好)
新建静态文件js
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); } } });
前端
{#{% load static %}#} {#<script src="{% static 'myset.js' %}"></script>#} {#<script>#} {# $('#d1').click(function () {#} {# $.ajax({#} {# url:'',#} {# type:'post',#} {#data:{'username':'jason'},#} {# // 第一种方式 自己手动获取#} {#data:{'username':'jason','csrfmiddlewaretoken':$('input[name="csrfmiddlewaretoken"]').val()},#} {# // 第二种方式 利用模板语法#} {#data:{'username':'jason','csrfmiddlewaretoken':'{{ csrf_token }}'},#} {# // 第三种 通用方式 引入外部js文件#} {# data:{'username':'jason'},#} {# success:function (data) {#} {# alert(data)#} {# }#} {# })#} {# })#} {#</script>#}
4.csrf相关装饰器
csrf相关装饰器 当我们网站整体都校验csrf的时候 我想让某几个视图函数不校验 当我们网站整体都不校验csrf的时候 我想让某几个视图函数校验 from django.views.decorators.csrf import csrf_exempt, csrf_protect from django.views import View9 from django.utils.decorators import method_decorator # @method_decorator(csrf_protect,name='post') # 第二种指名道姓的给类中某个方法装 # @method_decorator(csrf_exempt,name='post') # csrf_exempt 第二种方式不行 @method_decorator(csrf_exempt,name='dispatch') # 可以!!! class MyHome(View): # APIView # @method_decorator(csrf_protect) # 第三种 类中所有的方法都装 # @method_decorator(csrf_exempt) # csrf_exempt 第三种方式可以 def dispatch(self, request, *args, **kwargs): return super().dispatch(request,*args,**kwargs) def get(self,request): return HttpResponse('get') # @method_decorator(csrf_protect) # 第一种方式 直接给方法装饰 # @method_decorator(csrf_exempt) # csrf_exempt 第一种方式不行 def post(self,request): return HttpResponse('post') """ 给CBV加装饰器 推荐你使用模块method_decorator 我们自己写的装饰器和csrf_protect用法一致 唯独csrf_exempt是一个特例 只能给dispatch方法装 """
解释:FBV 校验
from django.views.decorators.csrf import csrf_exempt, csrf_protect
# @csrf_exempt # 不校验csrf csrf中间件打开,全局校验 设置此函数不校验 @csrf_protect # 校验csrf csrf注释,全局不校验,设置次函数校验 def index(request): print('我是视图函数index') def render(): return HttpResponse("你好啊 我是index里面的render函数") obj = HttpResponse("index") obj.render = render return obj
CBV校验:见上