今日内容概要
-
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.整理今日内容至个人博客或笔记中 4 2.自己编写参考django中间件实现功能可配置插拔式设计体会编程思想 5 '''