django中间件
'''
django中间件是django的门户
1、请求来的时候需要先经过中间件才能到达真正的django后端
2、响应走的时候最后也需要经过中间件才能发送出去
django自带七个中间件
'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',
'''
class SessionMiddleware(MiddlewareMixin):
def process_request(self, request):
session_key = request.COOKIES.get(settings.SESSION_COOKIE_NAME)
request.session = self.SessionStore(session_key)
def process_response(self, request, response):
return response
class CsrfViewMiddleware(MiddlewareMixin):
def process_request(self, request):
request.META['CSRF_COOKIE'] = csrf_token
def process_view(self, request, callback, callback_args, callback_kwargs)
return self._accept(request)
def process_response(self, request, response):
return response
class AuthenticationMiddleware(MiddlewareMixin):
def process_request(self, request):
request.user = SimpleLazyObject(lambda: get_user(request))
'''
django支持程序员自定义中间件并且暴露给程序员五个可以自定义的方法
1、必须掌握
process_request
process_response
2、了解
process_view
process_template_response
process_exception
'''
如何自定义中间件
'''
1、在项目名称或者应用下创建一个任意名称的文件夹
2、在该文件内创建一个任意名称的py文件
3、在该py文件内需要书写类(这个类必须继承MiddlewareMixin)
然后再这个类里面就可以自定义五个方法了
(需要几个就写几个)
4、需要将类的路径以字符串的形式注册到配置文件中才能生效
'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',
'自己写的中间件路径1',
'''
1、必须掌握
process_request(self,request)
1、请求来的时候需要经过某一个中间件里面的process_request方法
结束的顺序是按照配置文件中注册的中间件从上往下的顺序依次执行
2、如果中间件里面没有定义该方法,那么直接跳过执行下一个中间件
3、如果该方法返回了HttpResponse对象个,那么请求将不再继续往后执行
而是直接原路返回(校验失败不允许访问)
process_request方法就是用来做全局相关的所有限制功能
process_response(self,request,response)
1、响应走的时候需要经过每一个中间件里面的process_resopnse方法
该方法有两个额外的参数request,response
2、该方法必须返回也给HttpResponse对象
1、默认返回的就是形参response
2、你也可以返回自己的(HttpResponse对象)
3、顺序是按照配置文件中注册了的中间件从下往上依次经过
如果你没有定义,直接跳过执行下一个
#只要是形参带有response的方法,那么该方法就必须返回response或者HttpResponse对象
研究如果在第一个process_request方法就已经返回HttpResponse对象,那么响应走的时候就是经过所有的中间件里面的process_response还是其他情况
是其他情况
就是会直接走同级别的process_response返回
flask框架也有类似中间件但是它的规律:只要是返回数据了就必须经过所有中间件里面类似于process_response方法
2、了解
process_view
路由匹配成功之后执行视图函数之前,会自动执行中间件里面的该方法
顺序是按照配置文件中注册的中间件从上往下的顺序依次执行
process_template_response
返回的HttpResponse对象有render属性的时候才会触发
顺序是按照配置文件中注册的中间件从下往上的顺序依次执行
process_exception
当视图函数中出现异常的情况下触发
顺序是按照配置文件中注册了的中间件从下往上依次经过
csrf跨站请求伪造
"""
钓鱼网站
我搭建一个跟正规网站一模一样的界面(中国银行)
用户不小心进入到了我们的网站,用户给某个人打钱
打钱的操作确确实实是提交给了中国银行的系统,用户的钱也确确实实减少了
但是唯一不同的时候打钱的账户不适用户想要打的账户变成了一个莫名其妙的账户
大学英语四六级
考之前需要学生自己网站登陆缴费
内部本质
我们在钓鱼网站的页面 针对对方账户 只给用户提供一个没有name属性的普通input框
然后我们在内部隐藏一个已经写好name和value的input框
如何规避上述问题
csrf跨站请求伪造校验 ('django.middleware.csrf.CsrfViewMiddleware')
网站在给用户返回一个具有提交数据功能页面的时候会给这个页面加一个唯一标识
当这个页面朝后端发送post请求的时候 我的后端会先校验唯一标识,如果唯一标识不对直接拒绝(403 forbbiden)如果成功则正常执行
"""
如何符合校验
#form表单如何符合校验
<form action="" method="post">
{% csrf_token %} #记得不要注释掉settings里面的csrf
<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>
#Ajax如何符合校验
{% load static %}
<script src="{% static 'js/mysetup.js' %}"></script> #这两行是方式三才有的代码
<script>
$('#d1').click(function(){
$.ajax({
url:'',
type:'post',
//第一种方式
<!-- data:{'username':'lz','csrfmiddlewaretoken':$('[name=csrfmiddlewaretoken]').val()},-->
//第二种方式
<!-- data:{'username':'lz','csrfmiddlewaretoken':'{{csrf_token}}'},-->
//第三种方式
data:{'username':'lz'},
success:function(){
}
})
})
#其中方式3的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);
}
}
});
csrf相关装饰器
"""
1.网站整体都不校验csrf,就单单几个视图函数需要校验
2.网站整体都校验csrf,就单单几个视图函数不校验
"""
from django.views.decorators.csrf import csrf_protect,csrf_exempt
from django.utils.decorators import method_decorator
"""
csrf_protect 需要校验
针对csrf_protect符合我们之前所学的装饰器的三种玩法
csrf_exempt 忽视校验
针对csrf_exempt只能给dispatch方法加才有效
"""
# @csrf_exempt
# @csrf_protect
def transfer(request):
if request.method == 'POST':
username = request.POST.get('username')
target_user = request.POST.get('target_user')
money = request.POST.get('money')
print('%s给%s转了%s元'%(username,target_user,money))
return render(request,'transfer.html')
from django.views import View
# @method_decorator(csrf_protect,name='post') # 针对csrf_protect 第二种方式可以
# @method_decorator(csrf_exempt,name='post') # 针对csrf_exempt 第二种方式不可以
@method_decorator(csrf_exempt,name='dispatch')
class MyCsrfToken(View):
# @method_decorator(csrf_protect) # 针对csrf_protect 第三种方式可以
# @method_decorator(csrf_exempt) # 针对csrf_exempt 第三种方式可以
def dispatch(self, request, *args, **kwargs):
return super(MyCsrfToken, self).dispatch(request,*args,**kwargs)
def get(self,request):
return HttpResponse('get')
# @method_decorator(csrf_protect) # 针对csrf_protect 第一种方式可以
# @method_decorator(csrf_exempt) # 针对csrf_exempt 第一种方式不可以
def post(self,request):
return HttpResponse('post')
重要思想
__init__文件
import settings
import importlib
def send_all(content):
for path_str in settings.NOTIFY_LIST: #'notify.email.Email'
module_path,class_name = path_str.rsplit('.',maxsplit=1)
#module_path='notify.email' class_name='Email'
#1、利用字符串导入模块
module = importlib.import_module(module_path) #from notify import email
#2、利用反射获取类型
cls = getattr(module,class_name) #Email,QQ,Wechat
#3、生成类的对象
obj = cls()
#4、利用鸭子类型直接调用send方法
obj.send(content)
settings文件
NOTIFY_LIST=[
'notify.email.Email',
'notify.qq.QQ',
'notify.wechat.Wechat',
'notify.msg.Msg',
]
start文件
import notify
notify.send_all('你好呀')
功能模块
class Wechat(object):
def __init__(self):
pass
def send(self,content):
print('微信通知%s'%content)