国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 編程 > Python > 正文

詳解Django的CSRF認證實現

2020-01-04 14:24:51
字體:
來源:轉載
供稿:網友

什么是 CSRF

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

1.csrf原理

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

2.Django中的CSRF中間件

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

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

Django內置了很多中間件,其中之一就是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內置的CSRF中間件

3.Django中間件的執行流程

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

  • process_request
  • process_response
  • process_view
  • process_exception
  • process_template_response

Django中間件的執行順序

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

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

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

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

5.如果視圖函數或視圖類中使用render方法來向客戶端返回數據,則會觸發中間件中的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_tokendef 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的值 ,默認為 '_csrftoken' ,如果沒有獲取到 CSRF_USE_SESSIONS 的值,則從發送過來的請求中獲取 CSRF_COOKIE_NAME 的值,如果沒有定義則返回None。

再來看process_view方法

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

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

{% csrf_token %}

即可,否則會出現403的錯誤

Django,CSRF,認證

5.csrf_exempt裝飾器和csrf_protect裝飾器

5.1 基于Django FBV

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

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

from django.views.decorators.csrf import csrf_exempt@csrf_exempt def index(request):  pass

也可以把csrf_exempt裝飾器直接加在URL路由映射中,使某個視圖函數不經過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 中間件,但是想讓某個視圖函數進行CSRF驗證,則可以使用 csrf_protect 裝飾器

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

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,則不可以直接加在視圖類的視圖函數中了

此時有三種方式來對Django CBV進行CSRF驗證或者不進行CSRF驗證

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

from django.views.decorators.csrf import csrf_exemptfrom django.utils.decorators import method_decoratorclass 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_exempturlpatterns = [ url(r'^admin/', admin.site.urls), url(r'^auth/', csrf_exempt(views.UserAuthView.as_view())),]

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

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持VEVB武林網。


注:相關教程知識閱讀請移步到python教程頻道。
發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 名山县| 邛崃市| 罗平县| 怀化市| 出国| 琼中| 道真| 石狮市| 苗栗县| 罗源县| 宕昌县| 额济纳旗| 太康县| 中方县| 兴山县| 长汀县| 兴国县| 舟山市| 富源县| 兴文县| 丽水市| 荃湾区| 清苑县| 海伦市| 车致| 克拉玛依市| 桐乡市| 台南市| 西青区| 赤峰市| 滁州市| 稷山县| 儋州市| 黄石市| 左贡县| 蓬溪县| 五家渠市| 榕江县| 武宣县| 大余县| 周宁县|