中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

如何在Django中實現CSRF認證

發布時間:2021-06-01 17:44:39 來源:億速云 閱讀:236 作者:Leah 欄目:開發技術

如何在Django中實現CSRF認證?針對這個問題,這篇文章詳細介紹了相對應的分析和解答,希望可以幫助更多想解決這個問題的小伙伴找到更簡單易行的方法。

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_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的值 ,默認為 '_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_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())),
]

關于如何在Django中實現CSRF認證問題的解答就分享到這里了,希望以上內容可以對大家有一定的幫助,如果你還有很多疑惑沒有解開,可以關注億速云行業資訊頻道了解更多相關知識。

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

西贡区| 彭州市| 长宁区| 安溪县| 杭锦后旗| 万源市| 磐石市| 易门县| 寻甸| 彩票| 富裕县| 饶平县| 简阳市| 东乌珠穆沁旗| 淅川县| 建德市| 张家港市| 乌海市| 宁陵县| 含山县| 淳安县| 抚顺市| 宁蒗| 平乐县| 青浦区| 贡山| 禹州市| 江城| 徐汇区| 惠来县| SHOW| 偃师市| 霞浦县| 筠连县| 灵武市| 进贤县| 南昌市| 全椒县| 象山县| 郴州市| 南乐县|