70-django-中间件、csrf跨站请求伪造、csrf校验、csrf相关装饰器、模块补充、基于django中间件一个重要的编程思想

今日内容概要

  • django中间件
    • 首先django自带七个中间件,每个中间件都有各自对应的功能
    • 并且django还支持程序员自定义中间件
    • 你在用django开发项目的项目的时候,只要是涉及到全局相关的功能都可以使用中间件方便的完成
  • 全局用户身份校验
  • 全局用户权限校验(补充)
  • 全局访问频率校验
  • 基于django中间件一个重要的变成思想(补充)
  • csrf跨站请求伪造

今日内容详细

django中间件

 1 """
 2 django中间件是django的门户
 3 1.请求来的时候需要先经过中间件才能到达真正的django后端
 4 2.响应走的时候最后也需要经过中间件才能发送出去
 5 
 6 django自带七个中间件
 7 """
 8 django请求生命周期流程图
 9 
10 研究django中间件代码规律
11 MIDDLEWARE = [
12     'django.middleware.security.SecurityMiddleware',
13     'django.contrib.sessions.middleware.SessionMiddleware',
14     'django.middleware.common.CommonMiddleware',
15     'django.middleware.csrf.CsrfViewMiddleware',
16     'django.contrib.auth.middleware.AuthenticationMiddleware',
17     'django.contrib.messages.middleware.MessageMiddleware',
18     'django.middleware.clickjacking.XFrameOptionsMiddleware',
19 ]
20 
21 class SessionMiddleware(MiddlewareMixin):
22     def process_request(self, request):
23         session_key = request.COOKIES.get(settings.SESSION_COOKIE_NAME)
24         request.session = self.SessionStore(session_key)
25     def process_response(self, request, response):
26         return response
27       
28 class CsrfViewMiddleware(MiddlewareMixin):
29       def process_request(self, request):
30         csrf_token = self._get_token(request)
31         if csrf_token is not None:
32             # Use same token next time.
33             request.META['CSRF_COOKIE'] = csrf_token
34     def process_view(self, request, callback, callback_args, callback_kwargs):
35         return self._accept(request)
36 
37     def process_response(self, request, response):
38         return response
39       
40 class AuthenticationMiddleware(MiddlewareMixin):
41     def process_request(self, request):
42         request.user = SimpleLazyObject(lambda: get_user(request))
43 """
44 django支持程序员自定义中间件并且暴露给程序员五个可以自定义的方法
45     1.必须掌握
46         process_request
47         
48         process_response
49     2.了解即可
50         process_view
51             
52         process_template_response
53         
54         process_exception
55 """

如何自定义中间件

  1 """
  2 1.在项目名或者应用名下创建一个任意名称的文件夹
  3 2.在该文件夹内创建一个任意名称的py文件
  4 3.在该py文件内需要书写类(这个类必须继承MiddlewareMixin)
  5     然后在这个类里面就可以自定义五个方法了
  6     (这五个方法并不是全部都需要书写,用几个写几个)
  7 4.需要将类的路径以字符串的形式注册到配置文件中才能生效
  8 MIDDLEWARE = [
  9     'django.middleware.security.SecurityMiddleware',
 10     'django.contrib.sessions.middleware.SessionMiddleware',
 11     'django.middleware.common.CommonMiddleware',
 12     'django.middleware.csrf.CsrfViewMiddleware',
 13     'django.contrib.auth.middleware.AuthenticationMiddleware',
 14     'django.contrib.messages.middleware.MessageMiddleware',
 15     'django.middleware.clickjacking.XFrameOptionsMiddleware',
 16     '你自己写的中间件的路径1',
 17     '你自己写的中间件的路径2',
 18     '你自己写的中间件的路径3',
 19 ]
 20 
 21 """
 22 
 23 '''
 24 from django.utils.deprecation import MiddlewareMixin
 25 from django.shortcuts import render, HttpResponse, redirect
 26 
 27 
 28 class MyMiddleware1(MiddlewareMixin):
 29     def process_request(self, request):
 30         print('第一个自定的process_request方法')
 31         # return HttpResponse('第一个自定的process_request方法')
 32 
 33     def process_response(self, request, response):
 34         print('第一个自定的process_response方法')
 35         return response
 36 
 37     def process_view(self, request, view_name, *args, **kwargs):
 38         print(view_name, args, kwargs)
 39         print('第一个自定的process_view方法')
 40 
 41     def process_template_response(self, request, response):
 42         print('第一个自定的process_template_response方法')
 43         return response
 44 
 45     def process_exception(self, request, exception):
 46         print('第一个自定的process_exception方法')
 47         print(exception)
 48 
 49 
 50 class MyMiddleware2(MiddlewareMixin):
 51     def process_request(self, request):
 52         print('第二个自定的process_request方法')
 53 
 54     def process_response(self, request, response):
 55         print('第二个自定的process_response方法')
 56         return response
 57 
 58     def process_view(self, request, view_name, *args, **kwargs):
 59         print(view_name, args, kwargs)
 60         print('第二个自定的process_view方法')
 61 
 62     def process_template_response(self, request, response):
 63         print('第二个自定的process_template_response方法')
 64         return response
 65 
 66     def process_exception(self, request, exception):
 67         print('第二个自定的process_exception方法')
 68         print(exception)
 69 '''
 70 
 71 """
 72 1.必须掌握
 73         process_request 
 74             1.请求来的时候需要经过每一个中间件里面的process_request方法
 75             结果的顺序是按照配置文件中注册的中间件从上往下的顺序依次执行
 76             2.如果中间件里面没有定义该方法,那么直接跳过执行下一个中间件
 77             3.如果该方法返回了HttpResponse对象,那么请求将不再继续往后执行
 78             而是直接原路返回(校验失败不允许访问...)
 79             process_request方法就是用来做全局相关的所有限制功能
 80             
 81         process_response   (它的参数response就是django返回给浏览器的内容)
 82             1.响应走的时候需要经过每一个中间件里面的process_response方法
 83             该方法有两个额外的参数request,response
 84             2.该方法必须返回一个HttpResponse对象
 85                 1.默认返回的就是形参response
 86                 2.你也可以自己返回自己的
 87             3.顺序是按照配置文件中注册了的中间件从下往上依次经过
 88                 如果你没有定义的话 直接跳过执行下一个
 89         
 90         研究如果在第一个process_request方法就已经返回了HttpResponse对象,那么响应走的时候是经过所有的中间件里面的process_response还是有其他情况
 91         是其他情况
 92             就是会直接走同级别的process_reponse返回
 93         
 94         flask框架也有一个中间件但是它的规律
 95             只要返回数据了就必须经过所有中间件里面的类似于process_reponse方法
 96             
 97             
 98 2.了解即可
 99         process_view
100             路由匹配成功之后执行视图函数之前,会自动执行中间件里面的该放法
101             顺序是按照配置文件中注册的中间件从上往下的顺序依次执行
102             
103         process_template_response
104             返回的HttpResponse对象有render属性的时候才会触发
105                         只要形参中有response你就必须返回
106             顺序是按照配置文件中注册了的中间件从下往上依次经过
107 '''
108                         def index(request):
109                         print('在下index是也')
110                         obj = HttpResponse('在下index是也')
111                         def render():
112                          print('内部render方法')
113                         return HttpResponse('98K牛逼')
114                         obj.render = render
115                         return obj
116 '''            
117 
118         process_exception
119             当视图函数中出现异常的情况下触发
120                         参数exception就是报错信息
121             顺序是按照配置文件中注册了的中间件从下往上依次经过
122 """
123                 

csrf跨站请求伪造

 1 """
 2 钓鱼网站
 3     我搭建一个跟正规网站一模一样的界面(中国银行)
 4     用户不小心进入到了我们的网站,用户给某个人打钱
 5     打钱的操作确确实实是提交给了中国银行的系统,用户的钱也确确实实减少了
 6     但是唯一不同的时候打钱的账户不适用户想要打的账户变成了一个莫名其妙的账户
 7 
 8 大学英语四六级
 9     考之前需要学生自己网站登陆缴费
10 
11 内部本质
12     我们在钓鱼网站的页面 针对对方账户 只给用户提供一个没有name属性的普通input框
13     然后我们在内部隐藏一个已经写好name和value的input框
14 
15 如何规避上述问题
16     csrf跨站请求伪造校验
17         网站在给用户返回一个具有提交数据功能页面的时候会给这个页面加一个
18 唯一标识
19         当这个页面朝后端发送post请求的时候 我的后端会先校验唯一标识,如果
20 唯一标识不对直接拒绝(403 forbbiden)如果成功则正常执行    
21 """

如何符合校验

 1 # form表单如何符合校验
 2 <form action="" method="post">
 3     {% csrf_token %}
 4     <p>username:<input type="text" name="username"></p>
 5     <p>target_user:<input type="text" name="target_user"></p>
 6     <p>money:<input type="text" name="money"></p>
 7     <input type="submit">
 8 </form>
 9 
10 # ajax如何符合校验
11 // 第一种 利用标签查找获取页面上的随机字符串
12 {#data:{"username":'jason','csrfmiddlewaretoken':$('[name=csrfmiddlewaretoken]').val()},#}
13 // 第二种 利用模版语法提供的快捷书写
14 {#data:{"username":'jason','csrfmiddlewaretoken':'{{ csrf_token }}'},#}
15 // 第三种 通用方式直接拷贝js代码并应用到自己的html页面上即可
16 {% load static %}
17 <script src="{% static 'js/mysetup.js'%}"></script>
 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 
18 
19 function csrfSafeMethod(method) {
20   // these HTTP methods do not require CSRF protection
21   return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
22 }
23 
24 $.ajaxSetup({
25   beforeSend: function (xhr, settings) {
26     if (!csrfSafeMethod(settings.type) && !this.crossDomain) {
27       xhr.setRequestHeader("X-CSRFToken", csrftoken);
28     }
29   }
30 });
mysetup.js

csrf相关装饰器

 1 """
 2 1.网站整体都不校验csrf,就单单几个视图函数需要校验
 3 2.网站整体都校验csrf,就单单几个视图函数不校验
 4 """
 5 from django.views.decorators.csrf import csrf_protect,csrf_exempt
 6 from django.utils.decorators import method_decorator
 7 """
 8 csrf_protect  需要校验
 9     针对csrf_protect符合我们之前所学的装饰器的三种玩法
10 csrf_exempt   忽视校验
11     针对csrf_exempt只能给dispatch方法加才有效
12 """
13 # @csrf_exempt
14 # @csrf_protect
15 def transfer(request):
16     if request.method == 'POST':
17         username = request.POST.get('username')
18         target_user = request.POST.get('target_user')
19         money = request.POST.get('money')
20         print('%s给%s转了%s元'%(username,target_user,money))
21     return render(request,'transfer.html')
22 
23 
24 
25 from django.views import View
26 
27 # @method_decorator(csrf_protect,name='post')  # 针对csrf_protect 第二种方式可以
28 # @method_decorator(csrf_exempt,name='post')  # 针对csrf_exempt 第二种方式不可以
29 @method_decorator(csrf_exempt,name='dispatch')
30 class MyCsrfToken(View):
31     # @method_decorator(csrf_protect)  # 针对csrf_protect 第三种方式可以
32     # @method_decorator(csrf_exempt)  # 针对csrf_exempt 第三种方式可以
33     def dispatch(self, request, *args, **kwargs):
34         return super(MyCsrfToken, self).dispatch(request,*args,**kwargs)
35 
36     def get(self,request):
37         return HttpResponse('get')
38 
39     # @method_decorator(csrf_protect)  # 针对csrf_protect 第一种方式可以
40     # @method_decorator(csrf_exempt)  # 针对csrf_exempt 第一种方式不可以
41     def post(self,request):
42         return HttpResponse('post')

补充知识点-补充模块

1 # 模块:importlib
2 import importlib
3 res = 'myfile.b'
4 ret = importlib.import_module(res)  # from myfile import b
5 # 该方法最小只能到py文件名,不能再往下到文件里边变量名
6 print(ret)  # <module 'myfile.b' from 'C:\\Users\\Administrator\\PycharmProjects\\day70\\myfile\\b.py'>  

基于django中间件一个重要的编程思想

notify文件夹

__init__.py 文件

 1 import settings
 2 import importlib
 3 
 4 
 5 def send_all(content):
 6     for path_str in settings.NOTIFY_LIST:  # path_str是setting得NOTIFY_LIST列表中一个个的字符串  例如:'notify.email.Email'
 7         module_path, class_name = path_str.rsplit('.', maxsplit=1)
 8         # modult_path = 'notify.email'   class_name = 'Email'
 9         # 1.利用字符串导入模块
10         module = importlib.import_module(module_path)    # 这句话相当于: from notify import email
11         # 2.利用反射获取类名
12         cls = getattr(module, class_name)   # 这句话就可以拿到 Email、QQ、Wechat
13         # 3.生成类的对象
14         obj = cls()
15         # 4.利用鸭子类型直接调用send方法
16         obj.send(content)

email.py、qq.py、msg.py、wechat.py 文件

 1 ----email.py文件----
 2 
 3 class Email(object):
 4     def __init__(self):
 5         pass   # 发送邮箱需要得前期准备工作
 6 
 7     def send(self, content):
 8         print('邮箱通知:%s'%content)
 9 
10 
11 ----msg.py文件----
12 
13 class Msg(object):
14     def __init__(self):
15         pass  # 发送短信需要得前期准备工作
16 
17     def send(self, content):
18         print('短信通知:%s'%content)
19 
20 ----wechat.py文件----
21 
22 class Wechat(object):
23     def __init__(self):
24         pass  # 发送微信需要得前期准备工作
25 
26     def send(self, content):
27         print('微信通知:%s'%content)
28 
29 ----qq.py文件----
30 
31 class QQ(object):
32     def __init__(self):
33         pass  # 发送QQ需要得前期准备工作
34 
35     def send(self, content):
36         print('QQ通知:%s'%content)

settings.py 文件

1 NOTIFY_LIST = [
2     'notify.email.Email',
3     'notify.qq.QQ',
4     'notify.wechat.Wechat',
5     'notify.msg.Msg',
6 ]

start.py 文件

 1 import notify
 2 
 3 notify.send_all('快线上开课了')
 4 
 5 # 执行结果
 6 '''
 7 邮箱通知:快线上开课了
 8 QQ通知:快线上开课了
 9 微信通知:快线上开课了
10 短信通知:快线上开课了
11 '''

 今日测试

1 """
2 今日考题
3 1.什么是django中间件,它的作用是什么,如何自定义中间件,里面有哪些用户可以自定义的方法,这些方法有何特点
4 2.基于django中间件的功能设计,你有啥感悟和心得
5 3.什么是跨站请求伪造,你可以用一个具体的实例描述一下,django中如何防止及通过跨站请求伪造校验(form表单与ajax)
6 4.跨站请求伪造相关的装饰器有哪些,应用在FBV与CBV上的有什么异同
7 """

今日内容回顾

django中间件

 1 """
 2 django中间件类似于django的保安
 3     1.请求来的时候需要先经过中间件才能到达urls.py继续匹配
 4     2.响应走的时候最后也需要经过中间件才能真正离开django后端
 5 
 6 django中间件能够做的事情
 7     只要是涉及到项目全局的功能,你一定要想到中间件
 8     1.全局身份校验
 9     2.全局访问频率校验
10     3.全局权限校验
11     ...
12     
13 django默认有七个中间件(每个中间件其实就类似于一块独立的功能)
14 
15 django除了有自带的七个之外还支持用户自定义中间件并且暴露给用户五个可以自定义的方法
16 """
17 # 如何自定义中间件
18   1.在应用或者项目下创建一个任意名称的文件夹
19   2.在该文件夹内创建任意名称的py文件
20   3.在py文件内书写类 这个类需要继承所有中间件类都继承的MiddlewareMixin
21   4.需要在配置文件中书写类的完整路径
22 
23 # 需要掌握的两个
24     1.process_request(self,request)
25       1.请求来的时候会按照配置文件中注册的中间件从上往下依次经过每一个中间件里面的该方法,如果没有定义直接跳过
26     2.该方法也可以自己返回HttpResponse对象,一旦返回则请求不再继续往后执行直接原路返回(可以借助于该方法实现很多限制校验功能)
27   
28   2.process_response(self,request,response)
29       1.响应走的时候会按照配置文件中注册的中间件从下往上依次经过每一个中间件里面的该方法,如果没有定义直接跳过
30     2.形参response就是返回给前端浏览器的内容,也就意味着该方法要么将response返回要么自己返回一个HttpResponse对象
31     # 只要是形参中带有response的方法,那么该方法就必须返回response或者HttpResponse对象
32     
33   """
34   注意
35       当process_request返回HttpResponse对象之后会直接走同级别的process_response而不会将所有的process_response都走一遍
36       
37       但是在flask框架也有类似的中间件
38       但是它的特点只要返回响应就必须将所有类似于process_response功能方法全部走一遍
39   """
40   
41 # 了解即可的三个
42     1.process_view(self,view_name,*args,**kwargs)
43       路由匹配成功之后执行视图函数之前
44     
45   2.process_exception(self,request,exception)
46       当后端视图函数出现报错的时候
47   
48   3.process_template_response(self,request,response)
49       返回的HttpResponse对象必须含有render属性
django中间件

csrf跨站请求伪造

 1 """
 2 钓鱼网站
 3 本质:
 4     用假网站代替真网站,获取用户数据朝真网站提交,中途修改一些参数
 5     eg:网页银行转账的例子
 6     
 7 解决办法:
 8     在给用户返回的具有可以提交post请求的页面上添加一个唯一标记
 9     之后该页面发送post请求到后端,会先校验该唯一标记
10 """
11 # form表单如何获取
12     在form表单内书写{% csrf_token %}
13   <input type='hidden' name='csrfmiddlewaretoken' value='唯一的随机字符串'/>
14 
15 # ajax如何如何
16   1.自己利用标签查找获取值
17  data:{'csrfmiddlewaretoken':'$("[name=csrfmiddlewaretoken]").val()'}
18   2.利用模版语法
19  data:{'csrfmiddlewaretoken':'{{ csrf_token }}'}
20   3.通用的 js文件
21   拷贝固定的js代码导入到你的html页面上即可
csrf跨站请求伪造

csrf相关装饰器

 1 """
 2 from django.views.decorators.csrf import csrf_protect,csrf_exempt
 3 csrf_protect:需要校验csrf
 4     跟我们之前学习的三种给CBV加装饰器的玩法一样
 5 
 6 csrf_exempt:忽略校验csrf
 7     只能作用于dispatch方法
 8 
 9 他们两个在FBV上使用方式一致,就是普通的装饰器玩法
10 而在CBV上两者却有区别
11 """
csrf相关装饰器

参考django中间件功能设计扩展知识

 1 # 模块 importlib
 2     能够以字符串的形式帮助你导入模块,但是需要注意最小单位只能到模块名
 3 
 4 # 功能的插拔式设计
 5     1.配置文件注册功能
 6   2.importlib模块
 7   3.字符串切割split
 8   4.反射
 9   5.面向对象及鸭子类型
10 # 一定要总结吸收该思想
参考django中间件功能设计扩展知识

作业

1 '''
2 今日作业
3 1.整理今日内容至个人博客或笔记中
4 2.自己编写参考django中间件实现功能可配置插拔式设计体会编程思想
5 '''

猜你喜欢

转载自www.cnblogs.com/wgwg/p/13069744.html