Django之cbv加装饰器、中间件及CSRF_TOKEN跨站请求伪造

文章目录

      • 1、cbv加装饰器
      • 2、中间件
        • 2.1、定义
        • 2.2、如何自定义中间件
        • 2.3、中间件中的五个方法
          • 2.3.1、process_request和process_response
            • 2.3.1.1、process_request的作用
            • 2.3.1.2、process_request的作用
          • 2.3.2、process_view
          • 2.3.3、process_exception
          • 2.3.4、process_template_response
      • 3、CSRF_TOKEN跨站请求伪造
        • 3.1、钓鱼网站
        • 3.2、csrf跨站请求伪造校验(避免上述问题的方法)
        • 3.3、form表单提交
        • 3.4、ajax提交
        • 3.5、csrf相关装饰器

1、cbv加装饰器

CBV中django不建议直接给类的方法加装饰器

# 登录认证装饰器
def login_auth(func):
    def inner(request, *args, **kwargs):
        # 登录校验
        name = request.COOKIES.get('name')
        if name:
            res = func(request, *args, **kwargs)
            return res
        else:
            path = request.get_full_path()
            return redirect('/login/?returnUrl=%s' % path)
    return inner

from django.views import View
from django.utils.decorators import method_decorator
# 使用登录认证装饰器
# 方式一: 可以添加多个针对不同的方法加不同的装饰器
# @method_decorator(login_auth,name='get')
# @method_decorator(login_auth,name='post')
class UserInfo(View):
	# 方式二: 会直接作用于当前类里面的所有的方法
	@method_decorator(login_auth)
    def dispatch(self, request, *args, **kwargs):
        return super().dispatch(request,*args,**kwargs)
    # 方式三: 指名道姓
    @method_decorator(login_auth)
    def get(self, request, *args, **kwargs):
        return HttpResponse('userinfo get')
    
    @method_decorator(login_auth)
    def post(self, request, *args, **kwargs):
        return HttpResponse('userinfo post')

2、中间件

2.1、定义
中间件顾名思义,是介于request与response处理之间的一道处理过程,相对比较轻量级,并且在全局上改变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):
        csrf_token = self._get_token(request)
        if csrf_token is not None:
            # Use same token next time.
            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))
2.2、如何自定义中间件
1、在项目名或者应用名下创建一个任意名称的文件夹
2、在该文件夹内创建一个任意名称的py文件
3、在该py文件内需要书写类(这个类必须继承MiddlewareMixin)
   然后在这个类里面就可以自定义五个方法了
	(这五个方法并不是全部都需要书写,用几个写几个)
4、需要将类的路径以字符串的形式注册到配置文件中才能生效

MIDDLEWARE = [
	'你自己写的中间件的路径1',
    '你自己写的中间件的路径2',
    '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',
    '你自己写的中间件的路径3',
    '你自己写的中间件的路径4',
]

注意:你自己写的中间件的加载位置放在前面和放在后面是有影响的

2.3、中间件中的五个方法
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)
2.3.1、process_request和process_response

当用户发起请求的时候会依次经过所有的的中间件,这个时候的请求时process_request,最后到达views的函数中,views函数处理后,在依次穿过中间件,这个时候是process_response,最后返回给请求者
Django之cbv加装饰器、中间件及CSRF_TOKEN跨站请求伪造_第1张图片

process_request 

1、请求来的时候需要经过每一个中间件里面的process_request方法,结果的顺序是按照配置文件中注册的中间件从上往下的顺序依次执行
2、如果中间件里面没有定义该方法,那么直接跳过执行下一个中间件
3、如果该方法返回了HttpResponse对象,那么请求将不再继续往后执行,而是直接原路返回(校验失败不允许访问...)
process_request方法就是用来做全局相关的所有限制功能
process_response

1、响应走的时候需要经过每一个中间件里面的process_response方法,该方法有两个额外的参数request,response
2、该方法必须返回一个HttpResponse对象
	(1)默认返回的就是形参response
	(2)也可以自己返回自己的
3、顺序是按照配置文件中注册了的中间件从下往上依次经过,如果你没有定义的话 直接跳过执行下一个

如果在第一个process_request方法就已经返回了HttpResponse对象,那么响应走的时候就会直接走同级别的process_reponse返回,如下图:
Django之cbv加装饰器、中间件及CSRF_TOKEN跨站请求伪造_第2张图片

2.3.1.1、process_request的作用
可以写中间件,不管前端用什么编码格式,在requset.data中都有post的数据
频率限制(比如限制某个ip地址,一分钟只能访问5)
登录认证(只要没登录,重定向到login路径)
记录用户访问日志(比如ip,时间,访问路径)
2.3.1.2、process_request的作用
统一给所有(某几个路径)加cookie
统一给所有(某几个路径)加响应头

总结
1、中间件的process_request方法是在执行视图函数之前执行的
2、当配置多个中间件时,会按照MIDDLEWARE中的注册顺序,也就是列表的索引值,从前到后依次执行
3、不同中间件之间传递的request都是同一个对象

多个中间件中的process_response方法是按照MIDDLEWARE中的注册顺序倒序执行的,也就是说第一个中间件的process_request方法首先执行,而它的process_response方法最后执行,最后一个中间件的process_request方法最后一个执行,它的process_response方法是最先执行

2.3.2、process_view
process_view(self, request, view_func, view_args, view_kwargs)
该方法有四个参数
request是HttpRequest对象
view_func是Django即将使用的视图函数(它是实际的函数对象,而不是函数的名称作为字符串)
view_args是将传递给视图的位置参数的列表
view_kwargs是将传递给视图的关键字参数的字典,view_args和view_kwargs都不包含第一个视图参数(request)
Django会在调用视图函数之前调用process_view方法

路由匹配成功之后执行视图函数之前,会自动执行中间件里面的该放法
顺序是按照配置文件中注册的中间件从上往下的顺序依次执行

# 路由匹配成功,视图函数执行之前执行
def process_view(self, request, callback, callback_args, callback_kwargs):
    # print(callback)  callback就是视图函数
    # print(callback_args)
    # print(callback_kwargs)
    
    res=callback(request)  # 类似于装饰器的效果,可以在这个前面加逻辑,也可以在这个后面添加逻辑

    print("中间件的process_view")
    # return res

Django之cbv加装饰器、中间件及CSRF_TOKEN跨站请求伪造_第3张图片
注意:process_view如果有返回值,会越过其他的process_view以及视图函数,但是所有的process_response都还会执行

2.3.3、process_exception
process_exception(self, request, exception)
该方法两个参数:
一个HttpRequest对象
一个exception是视图函数异常产生的Exception对象

这个方法只有在视图函数中出现异常了才执行,它返回的值可以是一个None也可以是一个HttpResponse对象。如果是HttpResponse对象,Django将调用模板和中间件中的process_response方法,并返回给浏览器,否则将默认处理异常,如果返回None,则交给下一个中间件的process_exception方法来处理异常,它的执行顺序也是按照中间件注册顺序的倒序执行

当views出现错误时,如下图:
Django之cbv加装饰器、中间件及CSRF_TOKEN跨站请求伪造_第4张图片

2.3.4、process_template_response
该方法对视图函数返回值有要求,必须是一个含有render方法类的对象,才会执行此方法
返回的HttpResponse对象有render属性的时候才会触发
顺序是按照配置文件中注册了的中间件从下往上依次经过

class Test:
    def __init__(self,status,msg):
        self.status=status
        self.msg=msg
    def render(self):
        import json
        dic={'status':self.status,'msg':self.msg}

        return HttpResponse(json.dumps(dic))
def index(response):
    return Test(True,'测试')

3、CSRF_TOKEN跨站请求伪造

3.1、钓鱼网站
搭建一个跟正规网站一模一样的界面(比如xx银行)
用户不小心进入到了我们的网站,用户给某个人打钱
打钱的操作确实是提交给了xx银行的系统,用户的钱也确实减少了
但是唯一不同的是,打钱的账户不是用户想要打的账户,却变成了一个莫名其妙的账户

内部本质:
我们在钓鱼网站的页面,针对对方账户,只给用户提供一个没有name属性的普通input框
然后我们在内部隐藏一个已经写好name和value的input
3.2、csrf跨站请求伪造校验(避免上述问题的方法)
网站在给用户返回一个具有提交数据功能页面的时候会给这个页面加一个唯一标识
当这个页面朝后端发送post请求的时候 我的后端会先校验唯一标识,如果唯一标识不对就直接拒绝(403 forbbiden)如果成功则正常执行

后期中间件不能注释,每次发送post请求,都需要携带csrf_token随机字符串
3.3、form表单提交
在form表单中 {% csrf_token %}
3.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头中
headers:{'X-CSRFToken':'{{csrf_token}}'}

# jquery.cookie.js
在浏览器中对cookie进行增,删,查,改
前后端分离(js操作cookie)
3.5、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')

# 特殊的使用方式,在urls.py中
path('csrf_test/', csrf_exempt(views.csrf_test))

你可能感兴趣的:(python,中间件,django)