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>
70-django-中间件、csrf跨站请求伪造、csrf校验、csrf相关装饰器、模块补充、基于django中间件一个重要的编程思想
 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.整理今日内容至个人博客或笔记中
4 2.自己编写参考django中间件实现功能可配置插拔式设计体会编程思想
5 '''

 

上一篇:解决在TP5中无法使用快递鸟查询API接口方案


下一篇:jenkins忘记管理员登陆密码的补救措施