csrf装饰器

12.11.1 基本内容

  • csrf装饰器只可以加到dispatch
  • csrf_exempt(豁免) 某个视图不需要进行csrf校验,可以直接进行访问
  • csrf_protect 某个视图需要进行csrf校验 即使中间件注释也要校验
  • @method_decorator(csrf_exempt) 只能加到dispatch上
  • @method_decorator(csrf_protect ) 加到任意函数或类都可以,代表必须要csrf校验
    • 只使用这个,没有打开中间件,需要使用下面的 ensure_csrf_cookie来获取到cookie,因为中间件有个功能是设置cookie中的csrftoken
from django.views.decorators.csrf import csrg_exempt,csrf_protect,ensure_csrf_cookie
from django.utils.decorators import method_decorator
#ensure_csrf_cookie 确保生成cookie
# 一种是打开中间件,模板中使用 csrf token 
# 上述两种方式都可以
@method_decorator(csrf_exempt)  
def dispatch(self,request,*args,**kwargs):
    return ret

12.11.2 csrf功能

  1. csrf中间件执行 process_request:

    • 从cookie中获取csrftoken的值
    • csrftoken的值放入到request.META
  2. 执行process_view

    • 查看视图函数是否使用csrf_exempt装饰器,使用了就不进行校验了
    • 如果是GET HEAD OPTIONS TRACE 不进行csrf校验
    • 其他的比如 post put 是需要进行校验的
    • 进行csrf校验:
      1. 获取cookie中csrftoken的值和POST请求中csrfmiddlewaretoken的值,成功就接受请求,不成功就拒绝请求。
      2. 如果获取不到csrfmiddlewaretoken的值,通过request.META获取X-csrftoken的值,得到request_csrf_token的值,后再和cookie中的csrftoken的值比较。
  3. middleware源码解析

    • 'django.middleware.csrf.CsrfViewMiddleware',
    • CsrfViewMiddleware是个类, 在其中封装 并首先执行process_request,之中再执行_get_token方法,在这个方法中通过request.COOKIE['csrftoken'] 获取到具体的cookie中的csrftoken的值,之后判断下长度是否是64,然后通过request.META['CSRF_COOKIE'] = csrf_token 放入到请求头中
    • 执行完上个流程后,还会执行 process_view方法,来判断是否继续执行和校验,其中
    if getattr(request,'csrf_processing-done',False):
        return None  #代表如果执行了就不执行了
    if getattr(callback,'csrf_exempt', False):
        return None  #其中csrf装饰器@method_decorator(csrf_exempt)  中的crsf_exempt中有属性 wrapped_view.csrf_exempt = True 所以函数一旦有这个装饰器,也会执行结束,这也是csrf规避中间件校验的本质
    if request.method not in ('GET','HEAD','OPTIONS','TRACE'):
        #如果除了这四种,都要进行校验
        csrf_token = request.META.get('CSRF_COOKIE') #刚刚已经将cookie中的csrf_token信息放到请求头,这部是直接拿出来
        if csrf_token is None:
            return self._reject(request,REASON_NO_CSRF-COOKIE) #这步是返回403forbidden页面
        if request.method == 'POST':
            request_csrf_token = request.POST.get('csrfmiddlewaretoken','') #获取标签中hidden属性
        if request_csrf_token =='':
            request_csrf_token = request.META.get(settings.CSRF_HEADER_NAME,'') #结果是获得'HTTP_X_CSRFTOKEN'  真实的是 x-csrftoken  
        if not _cmpare_salted_tokens(request_csrf_token,csrf_token):
            return self._reject(request,REASON_BAD_TOKEN)   #比较 csrf_token (cookie中的csrf_token)   request_csrf_token(标签中的token或者设置的x-csrftoken)    
    return self._accept(request) #这部代表如果是上述四个方法,就不执行校验,返回True
    
    
posted @ 2019-11-02 17:22  Kn19ht  阅读(95)  评论(0)    收藏  举报