一、django的七个中间件

django中间件是浏览器和服务端交互的第一个门栏,请求来的时候需要通过中间件,响应走的时候也需要进过中间件

  1. MIDDLEWARE = [
  2. 'django.middleware.security.SecurityMiddleware'
  3. from django.middleware.security import SecurityMiddleware
  4. 'django.contrib.sessions.middleware.SessionMiddleware',
  5. 'django.middleware.common.CommonMiddleware',
  6. 'django.middleware.csrf.CsrfViewMiddleware',
  7. 'django.contrib.auth.middleware.AuthenticationMiddleware',
  8. 'django.contrib.messages.middleware.MessageMiddleware',
  9. 'django.middleware.clickjacking.XFrameOptionsMiddleware',
  10. ]
  11. # 以上代码相当于中间件的导入,通过一些内部的操作转换成下面的代码
  12. 'django.middleware.security.SecurityMiddleware'
  13. from django.middleware.security import SecurityMiddleware
  14. # 我们可以去这些中间件的源码里去找
  15. class SessionMiddleware(MiddlewareMixin):
  16. def process_request(self, request):
  17. session_key = request.COOKIES.get(settings.SESSION_COOKIE_NAME)
  18. request.session = self.SessionStore(session_key)
  19. def process_response(self, request, response):
  20. return response
  21. class CsrfViewMiddleware(MiddlewareMixin):
  22. def process_request(self, request):
  23. csrf_token = self._get_token(request)
  24. if csrf_token is not None:
  25. # Use same token next time.
  26. request.META['CSRF_COOKIE'] = csrf_token
  27. def process_view(self, request, callback, callback_args, callback_kwargs):
  28. return self._accept(request)
  29. def process_response(self, request, response):
  30. return response
  31. class AuthenticationMiddleware(MiddlewareMixin):
  32. def process_request(self, request):
  33. request.user = SimpleLazyObject(lambda: get_user(request))
  34. '''
  35. django支持程序员自定义中间件,并且有五个可以自定义的方法
  36. 1 必须掌握
  37. process_request
  38. prpcess_respone
  39. 2 了解即可
  40. process_view
  41. processs_template_respone
  42. process_exception
  43. '''

二、如何自定义中间件

1 自定义中间件的创建方式

  1. 先再项目下或者应用下创建一个任意名称的文件夹
  2. 在项目文件下内创建一个任意名称的py文件
  3. 在该py文件内书写类,这个类必须继承MiddlewareMixin,然后在这个类中自定制我们的需要的django提供的五个方法,用什么写什么,没有必须要写的
  4. 将类的路径以字符串的形式注册到配置文件中生效

2 django提供自定制中间件的五个方法

2.1 必须掌握两个方法

process_request

特点:

  • 所有请求来到服务端的时候先要依次(按照书写顺序的先后)经过所有中间件的process_request方法(没有就跳过)
  • 如果这个函数返回了一个HttpRespone对象,那么这个请求就会从这个函数开始原路返回(会先执行同中间件的process_respone,再依次往上返回)
  • 这些特点可以让这个方法作为全局相关的所有限制功能
  1. class Mymid1(MiddlewareMixin):
  2. def process_request(self,request):
  3. print('我是第一个中间件的process_request')

process_response

特点:

  • 所有响应返回的时候都要依次(与书写顺序相反)经过所有中间件的process_response方法(没有就跳过)
  • 必须返回respons对象
    • 返回的相当于是应该响应的数据
  • 或者返回一个HttpResponse对象
    • 返回的相当于是把应该相应的数据替换成我们自己写的数据(偷梁换柱)

ps:flask也有中间件,它的规律是只要返回了数据就必须要经过所有中间件里类似process_response方法

  1. from django.utils.deprecation import MiddlewareMixin
  2. from django.shortcuts import render,HttpResponse
  3. class Mymid1(MiddlewareMixin):
  4. def process_request(self,request):
  5. print('我是第一个中间件的process_request')
  6. def process_response(self,request,response):
  7. print('我是第一个中间件的process_respone')
  8. return HttpResponse('123') # 截胡
  9. class Mymid2(MiddlewareMixin):
  10. def process_request(self,request):
  11. print('我是第二个中间件的process_request')
  12. def process_response(self, request, response):
  13. print('我是第二个中间件的process_respone')
  14. return response # 正常返回

2.2 了解方法

process_view

  • 在路由匹配成功之后,执行视图函数之前会执行此方法
  • 所以只会在请求的时候执行
  • 执行顺序是中间件从上往下
  1. def process_view(self,request,view_name,args,kwargs):
  2. # print(view_name,args,kwargs)
  3. print('我是第一个中间件的process_view')

process_template_response

  • 当视图函数返回的HttpRespone对象中有render属性的时候会触发
  • 执行顺序是中间件从下往上
  1. # 中间件中
  2. def process_template_response(self, request, response):
  3. print('我是第二个中间件的process_template_response')
  4. return response
  5. # 视图函数中
  6. def index(request):
  7. print('我是视图函数index')
  8. obj = HttpResponse('index')
  9. def render():
  10. print('内部的render')
  11. return HttpResponse("O98K")
  12. obj.render = render
  13. return obj

process_exception

  • 当视图函数出现异常的时候触发(比如写了一个名字但是没定义)
  • 顺序按照中间件从下往上
  1. def process_exception(self, request, exception):
  2. print('我是第二个中间件的process_exception')
  3. print(exception) # 报错信息

三、csrf跨站请求伪造校验

1 案例及解决方案

案例:钓鱼网站

​ 用户在一个缴费钓鱼网站给自己制定的用户转钱,结果转到了另一个人账号上

原因:

​ 用户在打开缴费钓鱼网站的时候不会发现区别,钓鱼网站的页面会做的和正规页面一模一样,唯一的区别就是钓鱼网站内部有一个隐藏的input框去代替我们输入的对方账号的input框,最后向缴费服务端发送数据的时候,提交的是隐藏的数据。

如何避免上述问题

解决方案:csrf跨站请求伪造校验

原理:当页面朝后端发送post请求的时候,会顺带发送一个唯一标识码,这个唯一标识码是在渲染页面的时候服务端给页面的数据,如果唯一标识不对,直接拒绝访问(403 forbbiden),如果成功则正常执行

2 如何符合校验

form表单符合校验代码

  1. <form action="" method="post">
  2. {% csrf_token %}
  3. <input type="submit">
  4. </form>

ajax符合校验代码

  1. {% csrf_token %}
  2. <button id="d1">提交</button>
  3. // 方式三:推荐使用,导入一个写好的js文件去自动获取csrf
  4. {% load static %}
  5. <script src="{% static 'js/mysetup.js' %}"></script>
  6. <script>
  7. $('#d1').click(function () {
  8. $.ajax({
  9. url:'',
  10. type:'post',
  11. // 方式一:利用标签获取页面上的验证码
  12. data:{'username':'hz','csrfmiddlewaretoken':$('[name=csrfmiddlewaretoken]').val()},
  13. // 方式二:利用模版语言便捷写法
  14. data:{'username':'hz','csrfmiddlewaretoken':{% csrf_token %}},
  15. data:{'username':'hz'},
  16. success:function () {
  17. }
  18. })
  19. })
  20. </script>

mysetup.js代码

  1. function getCookie(name) {
  2. var cookieValue = null;
  3. if (document.cookie && document.cookie !== '') {
  4. var cookies = document.cookie.split(';');
  5. for (var i = 0; i < cookies.length; i++) {
  6. var cookie = jQuery.trim(cookies[i]);
  7. // Does this cookie string begin with the name we want?
  8. if (cookie.substring(0, name.length + 1) === (name + '=')) {
  9. cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
  10. break;
  11. }
  12. }
  13. }
  14. return cookieValue;
  15. }
  16. var csrftoken = getCookie('csrftoken');
  17. function csrfSafeMethod(method) {
  18. // these HTTP methods do not require CSRF protection
  19. return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
  20. }
  21. $.ajaxSetup({
  22. beforeSend: function (xhr, settings) {
  23. if (!csrfSafeMethod(settings.type) && !this.crossDomain) {
  24. xhr.setRequestHeader("X-CSRFToken", csrftoken);
  25. }
  26. }
  27. });

3 相关装饰器

  1. '''
  2. 以下两种情况用到两种不同的装饰器
  3. 1 网站整体都不校验csrf,就单独几个视图函数需要校验
  4. 2 网站整体都不校验csrf,就单独几个视图函数不校验
  5. '''
  6. from django.views.decorators.csrf import csrf_protect,csrf_exempt
  7. '''
  8. csrf_protect:需要校验,在CBV种三种装饰器方法都可以使用
  9. csrf_exempt:忽视校验,在CBV中只能使用给dispatch加装饰器的方法
  10. '''
  11. @csrf_exempt
  12. @csrf_protect
  13. def index(request):
  14. print('我是index函数')
  15. # print(index)
  16. if request.method=='POST':
  17. print(request.POST.get('username'))
  18. return HttpResponse('post index')
  19. return render(request,'index.html')
  20. # CBV
  21. # @method_decorator(csrf_protect,name='post') # 针对csrf_protect 第二种方式可以
  22. # @method_decorator(csrf_exempt,name='post') # 针对csrf_exempt 第二种方式不可以
  23. @method_decorator(csrf_exempt,name='dispatch')
  24. class MyCsrfToken(View):
  25. # @method_decorator(csrf_protect) # 针对csrf_protect 第三种方式可以
  26. # @method_decorator(csrf_exempt) # 针对csrf_exempt 第三种方式可以
  27. def dispatch(self, request, *args, **kwargs):
  28. return super(MyCsrfToken, self).dispatch(request,*args,**kwargs)
  29. def get(self,request):
  30. return HttpResponse('get')
  31. # @method_decorator(csrf_protect) # 针对csrf_protect 第一种方式可以
  32. # @method_decorator(csrf_exempt) # 针对csrf_exempt 第一种方式不可以
  33. def post(self,request):
  34. return HttpResponse('post')

四、重要补充知识点

补充

  1. # 通过一个模块实现和settins的中间件一样以字符串形式导入模块
  2. # 这个方法最小只能到py文件名
  3. import importlib
  4. res = 'myfile.b'
  5. # 下面等价于:from myfile import b
  6. ret = importlib.import_module(res)

思想

利用已学习的知识模仿django中间件导入

  1. # 创建一个包里面存有我们要使用的类
  2. # mymid.qq
  3. class QQ():
  4. def __init__(self):
  5. pass
  6. def send(self,msg):
  7. print(f'qq:{msg}')
  8. # mymid.wechat
  9. class Wechat():
  10. def __init__(self):
  11. pass
  12. def send(self,msg):
  13. print(f'wechat:{msg}')
  14. # 创建一个settings去存储这些类的路径
  15. # settings.py
  16. MYMID_DIR = [
  17. 'mymid.qq.QQ',
  18. 'mymid.wechat.Wechat',
  19. ]
  20. # 重点!!!!!!
  21. # mymid.__init__.py
  22. import importlib
  23. import settings
  24. def send_all(msg):
  25. for mymid in settings.MYMID_DIR:
  26. # 1 先用切片的方式获取模块路径和具体类名
  27. module_path,cls_name = mymid.rsplit('.',maxsplit=1)
  28. # print(module_path,cls_name)
  29. # 2 通过importlib模块以字符串的形式导入指定模块
  30. res = importlib.import_module(module_path)
  31. # 3 通过反射的方法获取类名
  32. cls = getattr(res,cls_name)
  33. obj = cls()
  34. # 4 利用鸭子类型直接调用send方法
  35. obj.send(msg)
  36. # start.py启动文件
  37. import mymid
  38. mymid.send_all('吃饭了')

day70 django中间件的更多相关文章

  1. Django数据操作F和Q、model多对多操作、Django中间件、信号、读数据库里的数据实现分页

    models.tb.objects.all().using('default'),根据using来指定在哪个库里查询,default是settings中配置的数据库的连接名称. 外话:django中引 ...

  2. django 中间件

    django处理一个Request的过程是首先通过django 中间件,然后再通过默认的URL方式进行的.所以说我们要做的就是在django 中间件这个地方把所有Request拦截住,用我们自己的方式 ...

  3. day20 FORM补充(随时更新),F/Q操作,model之多对多,django中间件,缓存,信号

    python-day20 1.FROM生成select标签的数据应该来源于数据库. 2.model 操作 F/Q  (组合查询) 3.model 多对多操作. 4.中间件 :在请求到达url前先会经过 ...

  4. Django学习之七:Django 中间件

    目录 Django 中间件 自定义中间件 - - - 大体两种方式 将中间件移除 实例 中间件加载源码阅读 总结 Django 中间件 Tips: 更新日志: 2019.01.31 更新django中 ...

  5. Django中间件的使用

    Django中间件的使用 中间件(middleware) 中间件应用于request与服务端之间和服务端与response之间,客户端发起请求到服务端接收可以通过中间件,服务端返回响应与客户端接收响应 ...

  6. Django中间件 及 form 实现用户登陆

    Django中间件 及 form 实现用户登陆 Form 验证 密码调用md5 加密存储 form.add_error("字段名", "错误信息") 自定义错误 ...

  7. Django 2.0 学习(20):Django 中间件详解

    Django 中间件详解 Django中间件 在Django中,中间件(middleware)其实就是一个类,在请求到来和结束后,Django会根据自己的规则在合适的时机执行中间件中相应的方法. 1. ...

  8. Django中间件的5种自定义方法

    阅读目录(Content) Django中间件 自定义中间件 中间件(类)中5种方法 中间件应用场景 回到顶部(go to top) Django中间件 在http请求 到达视图函数之前   和视图函 ...

  9. Python自动化之Django中间件

    django中间件 Django请求生命周期 中间件中可以定义方法,分别是 process_request(self,request) process_view(self, request, call ...

随机推荐

  1. 8、react 高阶组件

    1.高阶组件:封装 高阶组件使用得是react得一种模式,增强现有组件得功能 一个高阶组件就是一个函数,这个函数接收得是组件类作为参数得,并且返回得是一个新组件,再返回得新组件中有输入参数组件不具备得 ...

  2. 使用VBS实现SSH远程登录并自动执行命令

    set ws=createobject("wscript.shell")ws.run "Putty所在路径\putty.exe -ssh -pw 你的密码 用户名@192 ...

  3. (七)MySQL常见的数据类型、约束和标识列

    一.MySQL常见数据类型 1.数值型: ①整型:tinyint.smllint.mediumint.int/integer.bigint 图源:尚硅谷李玉婷 案例1:关键表格teacher,分别添加 ...

  4. Java8新特性之方法引用

    <Java 8 实战>学习笔记系列 定义 方法引用让你可以重复使用现有的方法定义,并像Lambda一样传递它,可以把方法引用看作针对仅仅涉及单一方法的Lambda的语法糖,使用它将减少自己 ...

  5. WPF入门(2)——依赖属性

    今天我们说说依赖属性 什么是依赖属性? 当然,学术定义依旧Please Baidu:https://baike.baidu.com/item/%E4%BE%9D%E8%B5%96%E5%B1%9E%E ...

  6. WeChair项目Alpha冲刺(5/10)

    团队项目进行情况 1.昨日进展    Alpha冲刺第五天 昨日进展: 前端:完成小程序登录态的定义 后端:成功部署项目到服务器并能通过域名访问项目 数据库:调整属性数据类型 2.今日安排 前端:完善 ...

  7. sharding-jdbc源码解析

    参考博客:https://cloud.tencent.com/developer/article/1529692 看sharding-jdbc支持XA协议重点看下面的代码 sharding-trans ...

  8. JavaWeb网上图书商城完整项目--day02-7.提交注册表单功能之流程分析

    1.点击注册之后将提交的信息传递到UserServlet的public String regist方法进行处理,然后将东西通过service进行处理 业务流程:

  9. Jmeter系列(34)- 详解 Counter 计数器

    如果你想从头学习Jmeter,可以看看这个系列的文章哦 https://www.cnblogs.com/poloyy/category/1746599.html 简单介绍 计数器的作用:循环递增生成数 ...

  10. 千金良方说:"我现在奉上179341字的MySQL资料包,还来得及吗?有"代码段、附录、和高清图!!"

    上一篇"上发布过"一不小心,我就上传了 279674 字的 MySQL 学习资料到 github 上了",我在更早之前,在微信公众号"老叶茶馆"上发布 ...