一、django的session原理流程
二、中间件
1、什么是中间件
中间件顾名思义,是介于request与response处理之间的一道处理过程,相对比较轻量级,并且在全局上改变django的输入与输出。因为改变的是全局,所以需要谨慎实用,用不好会影响到性能
2、中间件的作用
如果你想修改请求,例如被传送到view中的HttpRequest对象。 或者你想修改view返回的HttpResponse对象,这些都可以通过中间件来实现。
可能你还想在view执行之前做一些操作,这种情况就可以用 middleware来实现。
Django默认的中间件:(在django项目的settings模块中,有一个 MIDDLEWARE_CLASSES 变量,其中每一个元素就是一个中间件,如下图)
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',
]
每一个中间件都有具体的功能
三、自定义中间件
1、中间件的几个方法
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',
]
2、process_request和process_response(全局请求和响应)
process_request:所有请求来了都会经过它(尽量加判断),如果返回HttpResponse对象,将不再继续往前走
当用户发起请求的时候会依次经过所有的的中间件,这个时候的请求时process_request,最后到达views的函数中,views函数处理后,在依次穿过中间件,这个时候是process_response,最后返回给请求者
** process_request的作用**:频率限制(限制某个ip地址,一分钟只能几次)、登陆认证(只要没登陆,重定向到login路径)、记录用户访问日志(ip、时间、访问路径)
process_response的作用:统一给所有(某几个路径)加cookie、统一给所有(某几个路径)加响应头
3、自定义中间件
-写一个类,继承MiddlewareMixin
-里面写方法process_request(请求来了,一定会触发它的执行)、process_response(请求走了,一定会触发它的执行)
--在setting中配置(注意,放在前和放在后)
MIDDLEWARE = [
...
'app01.mymiddle.MyMiddleware1',
...
]
例如:
from django.utils.deprecation import MiddlewareMixin
from django.shortcuts import render,HttpResponse
class MyMiddleware1(MiddlewareMixin):
def process_request(self,request):
print("请求1来了")
def process_response(self,request,response):
print('请求1走了')
return response
# def process_view(self, request, callback, callback_args, callback_kwargs):
# print("中间件1的process_view")
# def process_exception(self,request,exception):
# print(exception)
class MyMiddleware2(MiddlewareMixin):
def process_request(self,request):
print("请求2来了")
def process_response(self,request,response):
print('请求2走了')
return response
# def process_view(self, request, callback, callback_args, callback_kwargs):
# print("中间件2的process_view")
# def process_exception(self,request,exception):
# print(exception)
注意:如果当请求到达请求2的时候直接不符合条件返回,即return HttpResponse("Md2中断"),程序将把请求直接发给中间件2返回,然后依次返回到请求者
由此总结一下:
中间件的process_request方法是在执行视图函数之前执行的。
当配置多个中间件时,会按照MIDDLEWARE中的注册顺序,也就是列表的索引值,从前到后依次执行的。
不同中间件之间传递的request都是同一个对象
4、process_view
路由匹配成功和视图函数执行之前执行(callback就是视图函数)
def process_view(self, request, callback, callback_args, callback_kwargs):
pass
5、process_exception
视图函数出错,会执行它(全局异常捕获)(记录日志,哪个ip地址,访问哪个路径,出的错)
###自定义中间件
from django.utils.deprecation import MiddlewareMixin
from django.shortcuts import render,HttpResponse
class MyMiddleware1(MiddlewareMixin):
def process_request(self,request):
print("请求1来了")
def process_response(self,request,response):
print('请求1走了')
return response
def process_view(self, request, callback, callback_args, callback_kwargs):
print("中间件1的process_view")
def process_exception(self,request,exception):
print(exception)
class MyMiddleware2(MiddlewareMixin):
def process_request(self,request):
print("请求2来了")
def process_response(self,request,response):
print('请求2走了')
return response
def process_view(self, request, callback, callback_args, callback_kwargs):
print("中间件2的process_view")
def process_exception(self,request,exception):
print(exception)
return render(request,"404.html")
###视图函数
from django.shortcuts import render,HttpResponse
# Create your views here.
def index(request):
a
print("view视图函数")
return HttpResponse("ok")
###执行结果
请求1来了
请求2来了
中间件1的process_view
中间件2的process_view
name 'a' is not defined
请求2走了
请求1走了
四、CSRF_TOKEN跨站请求伪造
1、介绍
https://www.cnblogs.com/liuqingzheng/p/9505044.html
2、代码演示csrf攻击
#视图函数
#登陆认证装饰器
def login_auth(func):
def inner(request,*args,**kwargs):
if request.session.get("name"):
return func(request,*args,**kwargs)
else:
path = request.get_full_path()
redirect("/app07/login/?returnUrl=%s"%path)
return inner
#登陆
def login(request):
if request.method == "GET":
return render(request,'login1.html')
else:
name = request.POST.get("name")
pwd = request.POST.get("pwd")
if name == "xiaohong" and pwd == "123":
#登陆成功,重定向
#以及写入session
request.session["name"] = name
path = request.GET.get("returnUrl")
if path:
return redirect(path)
else:
return redirect("/app07/bank/")
else:
return HttpResponse("用户名或名密码错误")
#银行
@login_auth
def bank(request):
return render(request,"bank.html")
#转账
@login_auth
def transfer(request):
# /transfer/?from=xiaohong&to=xiaoming&total=100
F = request.GET.get("from")
T = request.GET.get("to")
total = request.GET.get("total")
return HttpResponse("转账成功")
#在不同端口上写一个黑客函数
def hack(request):
return render(request,"hack.html")
#前端中黑客页面和银行页面地址指向转账
<body>
<a href="/app07/transfer/?from=xiaohong&to=xiaoming&total=100">点我转账</a>
</body>
解释上述例子:用户在登陆成功后,浏览器cookie中会自动生成一个session,用户在没有退出登陆,直接点开其他网站,由于自身携带的session还在,服务端会默认你是可以登入的,从而导致黑客中转账成功
3、django解决了csrf攻击,是用了中间件:django.middleware.csrf.CsrfViewMiddleware
4、后期中间件不能注释,每次发送post请求,都需要携带csrf_token随机字符串
-在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>
-在ajax中提交
<body>
{% csrf_token %} # 可以不写
<p>username:<input type="text" name="username"></p>
<p>pwd:<input type="text" name="pwd"></p>
<input type="submit" value="提交" id="btn">
<script>
$('#btn').click(function () {
$.ajax({
url:'',
method:'post',
data:{'username':$('[name="username"]').val(),'pwd':$('[name="pwd"]').val(),
#方式1:放到data中 'csrfmiddlewaretoken':$('[name="csrfmiddlewaretoken"]').val()
},
#方式二:'csrfmiddlewaretoken':‘{{ csrf_token }}’
#方式三:放到头中:
headers:{'X-CSRFToken':'{{ csrf_token }}'},
success:function (data) {
console.log("成功了")
console.log(data)
},
error:function (data) {
console.log("出现错误")
console.log(data)
}
})
})
</script>
</body>
#方式四:放在cookie中
获取cookie:$.cookie('csrftoken')
设置cookie:$.cookie('key','value')
删除cookie:$.cookie('key',null) # 参数null:代表删除此cookie
应用于前后端分离(js操作cookie)
<script>
$('#btn').click(function () {
#获取cookie中csrftoken的值
var token = $.cookie("csrftoken")
$.ajax({
url:'',
method:'post',
data:{'username':$('[name="username"]').val(),'pwd':$('[name="pwd"]').val(),
},
#可以写在头中
headers:{'X-CSRFToken':token},
success:function (data) {
console.log("成功了")
console.log(data)
},
error:function (data) {
console.log("出现错误")
console.log(data)
}
})
})
</script>
首先引入cookie的jquery插件
参考:https://www.cnblogs.com/SongHuiJuan/p/8065289.html
关于csrf的其他操作
1、全站禁用
注释掉中间件 'django.middleware.csrf.CsrfViewMiddleware',
2、全局使用,局部禁用csrf(在视图函数上加装饰器,中间件不能注释,此时这个视图函数已经没有csrf校验了)
from django.views.decorators.csrf import csrf_exempt,csrf_protect
@csrf_exempt
def csrf(request):
if request.method == "GET":
return render(request,"csrf.html")
else:
name = request.POST.get('name')
pwd = request.POST.get('pwd')
if name == "xiaohong" and pwd == "123":
return HttpResponse("登陆成功了")
else:
return HttpResponse("cuole")
3、全局禁用,局部使用csrf
在视图函数上在装饰器@csrf_protect
4、拓展:古怪的使用的方法,在urls.py中
装饰器直接放在路由内调用
path('csrf_test/', csrf_exempt(views))
视图函数上就不用再写装饰器了