欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

詳解Django的CSRF認(rèn)證實現(xiàn)

 更新時間:2018年10月09日 08:37:57   作者:renpingsheng  
這篇文章主要介紹了詳解Django的CSRF認(rèn)證實現(xiàn),詳細(xì)的介紹了csrf原理和實現(xiàn),小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧

什么是 CSRF

CSRF, Cross Site Request Forgery, 跨站點偽造請求。舉例來講,某個惡意的網(wǎng)站上有一個指向你的網(wǎng)站的鏈接,如果某個用戶已經(jīng)登錄到你的網(wǎng)站上了,那么當(dāng)這個用戶點擊這個惡意網(wǎng)站上的那個鏈接時,就會向你的網(wǎng)站發(fā)來一個請求,你的網(wǎng)站會以為這個請求是用戶自己發(fā)來的,其實呢,這個請求是那個惡意網(wǎng)站偽造的。

1.csrf原理

csrf要求發(fā)送post,put或delete請求的時候,是先以get方式發(fā)送請求,服務(wù)端響應(yīng)時會分配一個隨機字符串給客戶端,客戶端第二次發(fā)送post,put或delete請求時攜帶上次分配的隨機字符串到服務(wù)端進(jìn)行校驗

2.Django中的CSRF中間件

首先,我們知道Django中間件作用于整個項目。

在一個項目中,如果想對全局所有視圖函數(shù)或視圖類起作用時,就可以在中間件中實現(xiàn),比如想實現(xiàn)用戶登錄判斷,基于用戶的權(quán)限管理(RBAC)等都可以在Django中間件中來進(jìn)行操作

Django內(nèi)置了很多中間件,其中之一就是CSRF中間件

MIDDLEWARE_CLASSES = [
 'django.middleware.security.SecurityMiddleware',
 'django.contrib.sessions.middleware.SessionMiddleware',
 'django.middleware.common.CommonMiddleware',
 'django.middleware.csrf.CsrfViewMiddleware',
 'django.contrib.auth.middleware.AuthenticationMiddleware',
 'django.contrib.auth.middleware.SessionAuthenticationMiddleware',
 'django.contrib.messages.middleware.MessageMiddleware',
 'django.middleware.clickjacking.XFrameOptionsMiddleware',
]

上面第四個就是Django內(nèi)置的CSRF中間件

3.Django中間件的執(zhí)行流程

Django中間件中最多可以定義5個方法

  • process_request
  • process_response
  • process_view
  • process_exception
  • process_template_response

Django中間件的執(zhí)行順序

1.請求進(jìn)入到Django后,會按中間件的注冊順序執(zhí)行每個中間件中的process_request方法
    如果所有的中間件的process_request方法都沒有定義return語句,則進(jìn)入路由映射,進(jìn)行url匹配
    否則直接執(zhí)行return語句,返回響應(yīng)給客戶端

2.依次按順序執(zhí)行中間件中的process_view方法
    如果某個中間件的process_view方法沒有return語句,則根據(jù)第1步中匹配到的URL執(zhí)行對應(yīng)的視圖函數(shù)或視圖類
    如果某個中間件的process_view方法中定義了return語句,則后面的視圖函數(shù)或視圖類不會執(zhí)行,程序會直接返回

3.視圖函數(shù)或視圖類執(zhí)行完成之后,會按照中間件的注冊順序逆序執(zhí)行中間件中的process_response方法
    如果中間件中定義了return語句,程序會正常執(zhí)行,把視圖函數(shù)或視圖類的執(zhí)行結(jié)果返回給客戶端
    否則程序會拋出異常

4.程序在視圖函數(shù)或視圖類的正常執(zhí)行過程中
    如果出現(xiàn)異常,則會執(zhí)行按順序執(zhí)行中間件中的process_exception方法
    否則process_exception方法不會執(zhí)行
    如果某個中間件的process_exception方法中定義了return語句,則后面的中間件中的process_exception方法不會繼續(xù)執(zhí)行了

5.如果視圖函數(shù)或視圖類中使用render方法來向客戶端返回數(shù)據(jù),則會觸發(fā)中間件中的process_template_response方法

4.Django CSRF中間件的源碼解析

Django CSRF中間件的源碼

class CsrfViewMiddleware(MiddlewareMixin):

 def _accept(self, request):
  request.csrf_processing_done = True
  return None

 def _reject(self, request, reason):
  logger.warning(
   'Forbidden (%s): %s', reason, request.path,
   extra={
    'status_code': 403,
    'request': request,
   }
  )
  return _get_failure_view()(request, reason=reason)

 def _get_token(self, request):
  if settings.CSRF_USE_SESSIONS:
   try:
    return request.session.get(CSRF_SESSION_KEY)
   except AttributeError:
    raise ImproperlyConfigured(
     'CSRF_USE_SESSIONS is enabled, but request.session is not '
     'set. SessionMiddleware must appear before CsrfViewMiddleware '
     'in MIDDLEWARE%s.' % ('_CLASSES' if settings.MIDDLEWARE is None else '')
    )
  else:
   try:
    cookie_token = request.COOKIES[settings.CSRF_COOKIE_NAME]
   except KeyError:
    return None

   csrf_token = _sanitize_token(cookie_token)
   if csrf_token != cookie_token:
    # Cookie token needed to be replaced;
    # the cookie needs to be reset.
    request.csrf_cookie_needs_reset = True
   return csrf_token

 def _set_token(self, request, response):
  if settings.CSRF_USE_SESSIONS:
   request.session[CSRF_SESSION_KEY] = request.META['CSRF_COOKIE']
  else:
   response.set_cookie(
    settings.CSRF_COOKIE_NAME,
    request.META['CSRF_COOKIE'],
    max_age=settings.CSRF_COOKIE_AGE,
    domain=settings.CSRF_COOKIE_DOMAIN,
    path=settings.CSRF_COOKIE_PATH,
    secure=settings.CSRF_COOKIE_SECURE,
    httponly=settings.CSRF_COOKIE_HTTPONLY,
   )
   patch_vary_headers(response, ('Cookie',))

 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):
  if getattr(request, 'csrf_processing_done', False):
   return None

  if getattr(callback, 'csrf_exempt', False):
   return None

  if request.method not in ('GET', 'HEAD', 'OPTIONS', 'TRACE'):
   if getattr(request, '_dont_enforce_csrf_checks', False):
    return self._accept(request)

   if request.is_secure():
    referer = force_text(
     request.META.get('HTTP_REFERER'),
     strings_only=True,
     errors='replace'
    )
    if referer is None:
     return self._reject(request, REASON_NO_REFERER)

    referer = urlparse(referer)

    if '' in (referer.scheme, referer.netloc):
     return self._reject(request, REASON_MALFORMED_REFERER)

    if referer.scheme != 'https':
     return self._reject(request, REASON_INSECURE_REFERER)

    good_referer = (
     settings.SESSION_COOKIE_DOMAIN
     if settings.CSRF_USE_SESSIONS
     else settings.CSRF_COOKIE_DOMAIN
    )
    if good_referer is not None:
     server_port = request.get_port()
     if server_port not in ('443', '80'):
      good_referer = '%s:%s' % (good_referer, server_port)
    else:
     good_referer = request.get_host()

    good_hosts = list(settings.CSRF_TRUSTED_ORIGINS)
    good_hosts.append(good_referer)

    if not any(is_same_domain(referer.netloc, host) for host in good_hosts):
     reason = REASON_BAD_REFERER % referer.geturl()
     return self._reject(request, reason)

   csrf_token = request.META.get('CSRF_COOKIE')
   if csrf_token is None:
    return self._reject(request, REASON_NO_CSRF_COOKIE)

   request_csrf_token = ""
   if request.method == "POST":
    try:
     request_csrf_token = request.POST.get('csrfmiddlewaretoken', '')
    except IOError:
     pass

   if request_csrf_token == "":
    request_csrf_token = request.META.get(settings.CSRF_HEADER_NAME, '')

   request_csrf_token = _sanitize_token(request_csrf_token)
   if not _compare_salted_tokens(request_csrf_token, csrf_token):
    return self._reject(request, REASON_BAD_TOKEN)

  return self._accept(request)

 def process_response(self, request, response):
  if not getattr(request, 'csrf_cookie_needs_reset', False):
   if getattr(response, 'csrf_cookie_set', False):
    return response

  if not request.META.get("CSRF_COOKIE_USED", False):
   return response

  self._set_token(request, response)
  response.csrf_cookie_set = True
  return response

從上面的源碼中可以看到,CsrfViewMiddleware中間件中定義了process_request,process_view和process_response三個方法

先來看process_request方法

def _get_token(self, request): 
 if settings.CSRF_USE_SESSIONS: 
  try: 
   return request.session.get(CSRF_SESSION_KEY) 
  except AttributeError: 
   raise ImproperlyConfigured( 
    'CSRF_USE_SESSIONS is enabled, but request.session is not ' 
 'set. SessionMiddleware must appear before CsrfViewMiddleware ' 'in MIDDLEWARE%s.' % ('_CLASSES' if settings.MIDDLEWARE is None else '') 
   ) 
 else: 
  try: 
   cookie_token = request.COOKIES[settings.CSRF_COOKIE_NAME] 
  except KeyError: 
   return None 
 
 csrf_token = _sanitize_token(cookie_token) 
  if csrf_token != cookie_token: 
   # Cookie token needed to be replaced; 
 # the cookie needs to be reset. request.csrf_cookie_needs_reset = True 
 return csrf_token

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

從Django項目配置文件夾中讀取 CSRF_USE_SESSIONS 的值,如果獲取成功,則 從session中讀取CSRF_SESSION_KEY的值 ,默認(rèn)為 '_csrftoken' ,如果沒有獲取到 CSRF_USE_SESSIONS 的值,則從發(fā)送過來的請求中獲取 CSRF_COOKIE_NAME 的值,如果沒有定義則返回None。

再來看process_view方法

在process_view方法中,先檢查視圖函數(shù)是否被 csrf_exempt 裝飾器裝飾,如果視圖函數(shù)沒有被csrf_exempt裝飾器裝飾,則程序繼續(xù)執(zhí)行,否則返回None。接著從request請求頭中或者cookie中獲取攜帶的token并進(jìn)行驗證,驗證通過才會繼續(xù)執(zhí)行與URL匹配的視圖函數(shù),否則就返回 403 Forbidden 錯誤。

實際項目中,會在發(fā)送POST,PUT,DELETE,PATCH請求時,在提交的form表單中添加

{% csrf_token %}

即可,否則會出現(xiàn)403的錯誤

5.csrf_exempt裝飾器和csrf_protect裝飾器

5.1 基于Django FBV

在一個項目中,如果注冊起用了 CsrfViewMiddleware 中間件,則項目中所有的視圖函數(shù)和視圖類在執(zhí)行過程中都要進(jìn)行CSRF驗證。

此時想使某個視圖函數(shù)或視圖類不進(jìn)行CSRF驗證,則可以使用 csrf_exempt 裝飾器裝飾不想進(jìn)行CSRF驗證的視圖函數(shù)

from django.views.decorators.csrf import csrf_exempt

@csrf_exempt 
def index(request): 
 pass

也可以把csrf_exempt裝飾器直接加在URL路由映射中,使某個視圖函數(shù)不經(jīng)過CSRF驗證

from django.views.decorators.csrf import csrf_exempt 
 
from users import views 
 
urlpatterns = [ 
 url(r'^admin/', admin.site.urls), 
 url(r'^index/',csrf_exempt(views.index)), 
]

同樣的,如果在一個Django項目中,沒有注冊起用 CsrfViewMiddleware 中間件,但是想讓某個視圖函數(shù)進(jìn)行CSRF驗證,則可以使用 csrf_protect 裝飾器

csrf_protect裝飾器的用法跟csrf_exempt裝飾器用法相同 ,都可以加上視圖函數(shù)上方裝飾視圖函數(shù)或者在URL路由映射中直接裝飾視圖函數(shù)

from django.views.decorators.csrf import csrf_exempt 

@csrf_protect 
def index(request): 
 pass

或者

from django.views.decorators.csrf import csrf_protect 
 
from users import views 
 
urlpatterns = [ 
 url(r'^admin/', admin.site.urls), 
 url(r'^index/',csrf_protect(views.index)), 
]

5.1 基于Django CBV

上面的情況是基于Django FBV的,如果是基于Django CBV,則不可以直接加在視圖類的視圖函數(shù)中了

此時有三種方式來對Django CBV進(jìn)行CSRF驗證或者不進(jìn)行CSRF驗證

方法一,在視圖類中定義dispatch方法,為dispatch方法加csrf_exempt裝飾器

from django.views.decorators.csrf import csrf_exempt
from django.utils.decorators import method_decorator

class UserAuthView(View):

 @method_decorator(csrf_exempt)
 def dispatch(self, request, *args, **kwargs):
  return super(UserAuthView,self).dispatch(request,*args,**kwargs)

 def get(self,request,*args,**kwargs):
  pass

 def post(self,request,*args,**kwargs):
  pass

 def put(self,request,*args,**kwargs):
  pass

 def delete(self,request,*args,**kwargs):
  pass

方法二:為視圖類上方添加裝飾器

@method_decorator(csrf_exempt,name='dispatch')
class UserAuthView(View):
 def get(self,request,*args,**kwargs):
  pass

 def post(self,request,*args,**kwargs):
  pass

 def put(self,request,*args,**kwargs):
  pass

 def delete(self,request,*args,**kwargs):
  pass

方式三:在url.py中為類添加裝飾器

from django.views.decorators.csrf import csrf_exempt

urlpatterns = [
 url(r'^admin/', admin.site.urls),
 url(r'^auth/', csrf_exempt(views.UserAuthView.as_view())),
]

csrf_protect裝飾器的用法跟上面一樣

以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

  • python3對接mysql數(shù)據(jù)庫實例詳解

    python3對接mysql數(shù)據(jù)庫實例詳解

    這篇文章主要介紹了python3對接mysql數(shù)據(jù)庫,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-04-04
  • 使用Python的Scrapy框架編寫web爬蟲的簡單示例

    使用Python的Scrapy框架編寫web爬蟲的簡單示例

    這篇文章主要介紹了使用Python的Scrapy框架編寫web爬蟲的簡單示例,使用Python編寫爬蟲是Python應(yīng)用方面最得意的利器,Scrapy框架正是為爬蟲而生,需要的朋友可以參考下
    2015-04-04
  • 解決ImportError:DLL load failed while importing win32api:找不到指定的模塊

    解決ImportError:DLL load failed while impo

    在安裝pywin32后,可能會出現(xiàn)無法導(dǎo)入win32api的錯誤,一個有效的解決方案是運行pywin32_postinstall.py腳本,首先,打開cmd并切換到環(huán)境的Scripts文件夾,確保存在pywin32_postinstall.py文件
    2024-09-09
  • 淺談哪個Python庫才最適合做數(shù)據(jù)可視化

    淺談哪個Python庫才最適合做數(shù)據(jù)可視化

    數(shù)據(jù)可視化是任何探索性數(shù)據(jù)分析或報告的關(guān)鍵步驟,目前有許多非常好的商業(yè)智能工具,比如Tableau、googledatastudio和PowerBI等,本文就詳細(xì)的進(jìn)行對比,感興趣的可以了解一下
    2021-06-06
  • 七個生態(tài)系統(tǒng)核心庫[python自學(xué)收藏]

    七個生態(tài)系統(tǒng)核心庫[python自學(xué)收藏]

    無論你是想快速入手Python,還是想成為數(shù)據(jù)分析大神或者機器學(xué)習(xí)大佬,亦或者對Python代碼進(jìn)行優(yōu)化,本文的python庫都能為你提供一些幫助
    2021-08-08
  • python中g(shù)etaddrinfo()基本用法實例分析

    python中g(shù)etaddrinfo()基本用法實例分析

    這篇文章主要介紹了python中g(shù)etaddrinfo()基本用法,實例分析了Python中使用getaddrinfo方法進(jìn)行IP地址解析的基本技巧,需要的朋友可以參考下
    2015-06-06
  • Python 中閉包與裝飾器案例詳解

    Python 中閉包與裝飾器案例詳解

    這篇文章主要介紹了Python 中閉包與裝飾器案例詳解,本篇文章通過簡要的案例,講解了該項技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下
    2021-08-08
  • python操作日志的封裝方法(兩種方法)

    python操作日志的封裝方法(兩種方法)

    這篇文章主要介紹了python操作日志的封裝方法,本文通過實例代碼給大家介紹的非常詳細(xì),具有一定的參考借鑒價值 ,需要的朋友可以參考下
    2019-05-05
  • Pytorch使用shuffle打亂數(shù)據(jù)的操作

    Pytorch使用shuffle打亂數(shù)據(jù)的操作

    這篇文章主要介紹了Pytorch使用shuffle打亂數(shù)據(jù)的操作,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-05-05
  • PyCharm中鼠標(biāo)懸停在函數(shù)上時顯示函數(shù)和幫助的解決方法

    PyCharm中鼠標(biāo)懸停在函數(shù)上時顯示函數(shù)和幫助的解決方法

    這篇文章主要介紹了PyCharm中鼠標(biāo)懸停在函數(shù)上時顯示函數(shù)和幫助,本文給大家分享問題解決方法,對PyCharm鼠標(biāo)懸停函數(shù)上顯示函數(shù)的解決方法感興趣的朋友跟隨小編一起看看吧
    2022-11-11

最新評論