中间件
一、中间件
1.1 什么是中间件?
(1) Django默认自带7个中间件,中间件类似于django的门卫,数据在进入和离开时都需要经过中间件
(2) 那么中间件能干什么?
控制用户访问频率,全局登录校验,用户访问白名单,黑名单等
(3) settings.py里面的中间件配置信息:
MIDDLEWARE = [
'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',
]
(4) 中间件的执行规则:
1> 数据传到后端时:按照(3)中的顺序,从上到下,依次经过这些中间件处理
2> 当后端处理完之后,按照从下往上的执行顺序,经过这些中间件的处理之后传到前端
3> 还有一些规则,会在下面的代码中讲
(5) 中间件中主要有几个方法:
process_request(self,request)
process_view(self, request, callback, callback_args, callback_kwargs)
process_template_response(self,request,response)
process_exception(self, request, exception)
process_response(self, request, response)
1.2 怎么自定义中间件?
(1) 先导包(单独的py文件)
from django.utils.deprecation import MiddlewareMixin
from django.shortcuts import HttpResponse
(2) 自定义中间件
class Md1(MiddlewareMixin):
def process_request(self,request):
print("Md1请求")
def process_response(self,request,response):
print("Md1返回")
return response
class Md2(MiddlewareMixin):
def process_request(self,request):
print("Md2请求")
#return HttpResponse("Md2中断")
def process_response(self,request,response):
print("Md2返回")
return response
(3) 在view中定义一个视图函数
def index(request):
print("view函数...")
return HttpResponse("OK")
(4) 在settings.py中的MIDDLEWARE里注册自定义中间件
ps:执行结果
Md1请求
Md2请求
view函数...
Md2返回
Md1返回
ps2:如果当请求到达请求2的时候直接不符合条件返回,即return HttpResponse("Md2中断"),程序将把请求直接发给中间件2返回,然后依次返回到请求者,结果如下:
返回Md2中断的页面,后台打印如下:
Md1请求
Md2请求
Md2返回
Md1返回
总结:
(1) 中间件的process_request方法是在执行视图函数之前执行的。
(2) 当配置多个中间件时,会按照MIDDLEWARE中的注册顺序,也就是列表的索引值,从前到后依次执行的。
(3) 不同中间件之间传递的request都是同一个对象。
多个中间件中的process_response方法是按照MIDDLEWARE中的注册顺序倒序执行的,
---> 第一个中间件的process_request方法首先执行,而它的process_response方法最后执行,
最后一个中间件的process_request方法最后一个执行,它的process_response方法是最先执行。
二、csrf(跨站请求伪造)
2.1 举个栗子🌰:
钓鱼网站:银行转账的路径,可以拿到,然后你做一个跟银行一模一样的页面,也朝银行的接口提交数据,当用户在钓鱼网站输入对方账户名和转账金额之后,点击发送。其实内部是将对方账户换成了钓鱼网站的造假人员的账户,造成你转账转错账户的情况。
2.2 如何设置csrf_token
(1) 在form表单中应用
<form action="" method="post">
{% csrf_token %}
<p>用户名:<input type="text" name="name"></p>
<p>密码:<input type="text" name="password"></p>
<p><input type="submit"></p>
</form>
(2) Ajax中应用
<body>
<form action="" method="post">
{% csrf_token %}
<p>用户名:<input type="text" name="name"></p>
<p>密码:<input type="text" name="password" id="pwd"></p>
<p><input type="submit"></p>
</form>
<button class="btn">点我</button>
</body>
<script>
$(".btn").click(function () {
$.ajax({
url: '',
type: 'post',
data: {
'name': $('[name="name"]').val(),
'password': $("#pwd").val(),
'csrfmiddlewaretoken': $('[name="csrfmiddlewaretoken"]').val()
},
success: function (data) {
console.log(data)
}
})
})
</script>
</html>
2.3 csrf_token使用范围
# 只想给某个视图函数加上csrf校验
from django.views.decorators.csrf import csrf_exempt,csrf_protect
# 局部禁用
@csrf_exempt
def index(request):
pass
# 局部使用
@csrf_protect
def login(request):
pass
# CBV比较特殊,不能单独加在某个方法上
# 只能加在类上或dispatch方法上
from django.utils.decorators import method_decorator
from django.views.decorators.csrf import csrf_exempt,csrf_protect
@method_decorator(csrf_exempt,name='dispatch') # 第一种
class Csrf_Token(View):
@method_decorator(csrf_exempt) # 第二种
def dispatch(self,request,*args,**kwargs):
res = super().dispatch(request,*args,**kwargs)
return res
@method_decorator(csrf_exempt) # 这里这么写不行!!!
def get(self,request):
pass
def post(self,request):
pass
三、中间件版登录验证
中间件版的登录验证需要依靠session,所以数据库中要有django_session表。
urls.py
from app02 import views as v2 urlpatterns = [ url(r'^admin/', admin.site.urls), url(r'^login/',v2.login), url(r'^home/',v2.home), url(r'^index/',v2.index) ]
views.py
from django.shortcuts import render,redirect,HttpResponse from app02 import models # Create your views here. def login(request): error_msg='' if request.method=='POST': username=request.POST.get('username') password=request.POST.get('password') user_obj=models.User.objects.filter(username=username,password=password) if user_obj: #设置session request.session['login']='ok' #获取用户想直接访问的URL url=request.GET.get('next') #如果有,就跳转到客户初始想访问的URL if not url: #没有则默认跳转到home页面 url='/home/' return redirect(url) else: error_msg='username or password error!' return render(request,'login.html',{'error_msg':error_msg}) def home(request): return HttpResponse('<h1>这是home页面 只有登录了才能看到</h1>') def index(request): return HttpResponse('<h1>这是index页面 也只有登录了才能看到<h1>')
login.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>登陆页面</title> <meta name="viewport" content="width=device-width, initial-scale=1"> </head> <body> <form action="" method="post"> {% csrf_token %} <label for="">username:<input type="text" name="username"></label> <label for="">password:<input type="password" name="password"></label> <input type="submit" value="submit"> </form> <h1 style="color: red">{{ error_msg }}</h1> </body> </html>
middlewares.py
from django.utils.deprecation import MiddlewareMixin from django.shortcuts import redirect class Check_Login(MiddlewareMixin): def process_request(self,request): next_url=request.path_info if not next_url.startswith('/login/'): is_login=request.session.get('login','') if not is_login: return redirect('/login/?next={}'.format(next_url))
在settings.py中注册
MIDDLEWARE = [ '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', 'middleware.my_middleware.Check_Login', ]