Day14 session原理和中间件
views视图函数
def index(request):
return HttpResponse('视图函数好了!')
def login(request):
return HttpResponse('我是登录函数')
已在urls注册
一、什么是中间件
它是一个轻量、低级别的插件系统,用于在全局范围内改变Django的输入和输出。每个中间件组件都负责做一些特定的功能。
简单来说:中间件是帮助我们在视图函数执行之前和执行之后都可以做一些额外的操作,它本质上就是一个自定义类,类中定义了几个方法,Django框架会在请求的特定的时间去执行这些方法。
MIDDLEWARE的配置项
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',
'app01.Mymiddleware.Mymiddleware.Middle1',
'app01.Mymiddleware.Mymiddleware.Middle2',
]
MIDDLEWARE配置项是一个列表(列表是有序的,记住这一点,后面你就知道为什么要强调有序二字),列表中是一个个字符串,这些字符串其实是一个个类,也就是一个个中间件。
-请求来的时候从上往下执行:process_request
-请求走的时候从下往上执行:process_response
1.process_request方法
class Middle1(MiddlewareMixin):
def process_request(self, request):
print('这是通过我Middle1的request!')
class Middle2(MiddlewareMixin):
def process_request(self, request):
print('这是通过我Middle2的request!')
这里是定义的两个请求方法,然后我们运行项目,看看结果如何
由此总结一下:
- 中间件的process_request方法是在执行视图函数之前执行的。
- 当配置多个中间件时,会按照MIDDLEWARE中的注册顺序,也就是列表的索引值,从前到后依次执行的。
- 不同中间件之间传递的request都是同一个对象
我们可以看他运行的方式,是我们注册方式的从上而下,会一次执行每一个中间件,就像猪肉质检层层把关
2.process_response方法
class Middle1(MiddlewareMixin):
def process_request(self, request):
print('这是通过我Middle1的request!')
def process_response(self, request, response):
print('这是通过我Middle1的response!')
return response # 必须要返回response
class Middle2(MiddlewareMixin):
def process_request(self, request):
print('这是通过我Middle2的request!')
def process_response(self, request, response):
print('这是通过我Middle2的response!')
return response
然后我们来运行一下
运行结果是不是很像 之前的多个装饰器
注意:
定义process_response方法时,必须给方法传入两个形参,request和response。request就是上述例子中一样的对象,response是视图函数返回的HttpResponse对象(也就是说这是Django后台处理完之后给出一个的一个具体的视图)。该方法的返回值(必须要有返回值)也必须是HttpResponse对象。如果不返回response而返回其他对象,则浏览器不会拿到Django后台给他的视图,而是我的中间件中返回的对象
这里我们来修改一下返回的对象
class Middle2(MiddlewareMixin):
def process_request(self, request):
print('这是通过我Middle2的request!')
def process_response(self, request, response):
print('这是通过我Middle2的response!')
return HttpResponse('我是Middle2自定义的response')
3.process_view方法
参数配置
该方法有四个参数
request是HttpRequest对象。
view_func是Django即将使用的视图函数。 (它是实际的函数对象,而不是函数的名称作为字符串。)
view_args是将传递给视图的位置参数的列表.
view_kwargs是将传递给视图的关键字参数的字典。 view_args和view_kwargs都不包含第一个视图参数(request)。
Django会在调用视图函数之前调用process_view方法。
class Middle1(MiddlewareMixin):
def process_request(self, request):
print('这是通过我Middle1的request!')
def process_response(self, request, response):
print('这是通过我Middle1的response!')
return response # 必须要返回response
def process_view(self, request,view_func, view_args, view_kwargs):
print(request.method)
print(view_func.__name__) # 会自动捕获所调用的函数,也就是根据url分发的网址与函数关系
print(view_func)
return HttpResponse('54088')
class Middle2(MiddlewareMixin):
def process_request(self, request):
print('这是通过我Middle2的request!')
def process_response(self, request, response):
print('这是通过我Middle2的response!')
return response
def process_view(self, request,view_func, view_args, view_kwargs):
print(view_func.__name__)
print(view_func)
print(view_args)
return HttpResponse('54099')
试一试,访问login页面
总结:
- 在urls.py之后在执行真正的视图函数之前
- 按照在列表中注册的顺序依次执行
- 返回值1.返回None,放行
- 返回值2.返回响应对象,就直接跳出,倒序依次执行所有中间件的process_response方法
like this
4.process_exception方法
process_exception(self, request, exception)
一个HttpRequest对象
一个exception是视图函数异常产生的Exception对象。
这个方法只有在视图函数中出现异常了才执行,它返回的值可以是一个None也可以是一个HttpResponse对象(程序bug返回404)。如果是HttpResponse对象,Django将调用模板和中间件中的process_response方法,并返回给浏览器,否则将默认处理异常。如果返回一个None,则交给下一个中间件的process_exception方法来处理异常。它的执行顺序也是按照中间件注册顺序的倒序执行。
class Middle1(MiddlewareMixin):
def process_request(self, request):
print('这是通过我Middle1的request!')
def process_response(self, request, response):
print('这是通过我Middle1的response!')
return response # 必须要返回response
def process_view(self, request, view_func, view_args, view_kwargs):
pass
def process_exception(self, request, exception):
print('middle1的', exception)
return HttpResponse('404')
class Middle2(MiddlewareMixin):
def process_request(self, request):
print('这是通过我Middle2的request!')
def process_response(self, request, response):
print('这是通过我Middle2的response!')
return response
def process_view(self, request, view_func, view_args, view_kwargs):
pass
def process_exception(self, request, exception):
print('middle2的', exception)
print('我捕获到了错误,但是我不想处理,留给Middle1')
5.process_template_response方法(用的比较少)
process_template_response(用的比较少)
process_template_response(self, request, response)
它的参数,一个HttpRequest对象,response是TemplateResponse对象(由视图函数或者中间件产生)。
process_template_response是在视图函数执行完成后立即执行,但是它有一个前提条件,那就是视图函数返回的对象有一个render()方法(或者表明该对象是一个TemplateResponse对象或等价方法)。
总结
如果request也有返回值,也是直接到自己位置的response,之前的response(3,4,5,6)不会走,直接就跳过了
二、CSRF_TOKEN跨站请求伪造
CSRF(Cross-site request forgery)跨站请求伪造,也被称为“One Click Attack”或者Session Riding,通常缩写为CSRF或者XSRF,是一种对网站的恶意利用。尽管听起来像跨站脚本(XSS),但它与XSS非常不同,XSS利用站点内的信任用户,而CSRF则通过伪装来自受信任用户的请求来利用受信任的网站。与XSS攻击相比,CSRF攻击往往不大流行(因此对其进行防范的资源也相当稀少)和难以防范,所以被认为比XSS更具危险性
可以这样来理解:
攻击者盗用了你的身份,以你的名义发送恶意请求,对服务器来说这个请求是完全合法的,但是却完成了攻击者所期望的一个操作,比如以你的名义发送邮件、发消息,盗取你的账号,添加系统管理员,甚至于购买商品、虚拟货币转账等。 如下:其中Web A为存在CSRF漏洞的网站,Web B为攻击者构建的恶意网站,User C为Web A网站的合法用户
1. CSRF攻击原理
如下图:
从上图可以看出,要完成一次CSRF攻击,受害者必须依次完成两个步骤:
1.登录受信任网站A,并在本地生成Cookie。
2.在不登出A的情况下,访问危险网站B。
看到这里,你也许会说:“如果我不满足以上两个条件中的一个,我就不会受到CSRF的攻击”。是的,确实如此,但你不能保证以下情况不会发生:
1.你不能保证你登录了一个网站后,不再打开一个tab页面并访问另外的网站。
2.你不能保证你关闭浏览器了后,你本地的Cookie立刻过期,你上次的会话已经结束。(事实上,关闭浏览器不能结束一个会话,但大多数人都会错误的认为关闭浏览器就等于退出登录/结束会话了…)
3.上图中所谓的攻击网站,可能是一个存在其他漏洞的可信任的经常被人访问的网站。
2. CSRF攻击防范
说简单点我们的django已经帮我们做到的防范,也就是多重校验,标签
crsf_token
3.在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>
4.在Ajax中应用:
方式一:放到data中
$.ajax({
url: '/csrf_test/',
method: 'post',
data: {'name': $('[name="name"]').val(),
'password': $('[name="password"]').val(),
'csrfmiddlewaretoken':$('[name="csrfmiddlewaretoken"]').val()
},
success: function (data) {
console.log('成功了')
console.log(data)
},
error: function (data) {
console.log('xxxxx')
console.log(data)
}
})
方式二:放到data中
'csrfmiddlewaretoken':'{{ csrf_token }}'
方式三:放到头中
headers:{'X-CSRFToken':'{{csrf_token}}'},
# jquery.cookie.js
-在浏览器中对cookie进行增,删,查,改
-前后端分离(js操作cookie)
# 全局使用,局部禁csrf
-在视图函数上加装饰器
from django.views.decorators.csrf import csrf_exempt,csrf_protect
# 全局启用,局部禁用(中间件不能注释,这个视图函数,已经没有csrf校验了)
# @csrf_exempt
# def csrf_test(request):
# if request.method=='GET':
# return render(request,'csrf_test.html')
# else:
# name=request.POST.get('name')
# password=request.POST.get('password')
# print(name)
# print(password)
# return HttpResponse('登录成功')
# 全局禁用,局部使用csrf
@csrf_protect
def csrf_test(request):
if request.method=='GET':
return render(request,'csrf_test.html')
else:
name=request.POST.get('name')
password=request.POST.get('password')
print(name)
print(password)
return HttpResponse('登录成功')
# 古怪的使用方式,在urls.py中
path('csrf_test/', csrf_exempt(views.csrf_test))