最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

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

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

什么是 CSRF

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

1.csrf原理

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

2.Django中的CSRF中間件

首先,我們知道Django中間件作用于整個(gè)項(xiàng)目。

在一個(gè)項(xiàng)目中,如果想對全局所有視圖函數(shù)或視圖類起作用時(shí),就可以在中間件中實(shí)現(xiàn),比如想實(shí)現(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',
]

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

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

Django中間件中最多可以定義5個(gè)方法

  • process_request
  • process_response
  • process_view
  • process_exception
  • process_template_response

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

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

2.依次按順序執(zhí)行中間件中的process_view方法
    如果某個(gè)中間件的process_view方法沒有return語句,則根據(jù)第1步中匹配到的URL執(zhí)行對應(yīng)的視圖函數(shù)或視圖類
    如果某個(gè)中間件的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í)行
    如果某個(gè)中間件的process_exception方法中定義了return語句,則后面的中間件中的process_exception方法不會繼續(xù)執(zhí)行了

5.如果視圖函數(shù)或視圖類中使用render方法來向客戶端返回?cái)?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三個(gè)方法

先來看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項(xiàng)目配置文件夾中讀取 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)行驗(yàn)證,驗(yàn)證通過才會繼續(xù)執(zhí)行與URL匹配的視圖函數(shù),否則就返回 403 Forbidden 錯(cuò)誤。

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

{% csrf_token %}

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

5.csrf_exempt裝飾器和csrf_protect裝飾器

5.1 基于Django FBV

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

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

from django.views.decorators.csrf import csrf_exempt

@csrf_exempt 
def index(request): 
 pass

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

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)), 
]

同樣的,如果在一個(gè)Django項(xiàng)目中,沒有注冊起用 CsrfViewMiddleware 中間件,但是想讓某個(gè)視圖函數(shù)進(jìn)行CSRF驗(yàn)證,則可以使用 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ù)中了

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

方法一,在視圖類中定義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)文章

  • python通過opencv實(shí)現(xiàn)圖片裁剪原理解析

    python通過opencv實(shí)現(xiàn)圖片裁剪原理解析

    這篇文章主要介紹了python通過opencv實(shí)現(xiàn)圖片裁剪原理解析,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-01-01
  • 淺談django channels 路由誤導(dǎo)

    淺談django channels 路由誤導(dǎo)

    這篇文章主要介紹了淺談django channels 路由誤導(dǎo),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-05-05
  • 支持PyTorch的einops張量操作神器用法示例詳解

    支持PyTorch的einops張量操作神器用法示例詳解

    這篇文章主要為大家介紹了支持PyTorch的einops張量操作神器用法示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步早日升職加薪
    2021-11-11
  • python中的mock接口開發(fā)示例詳解

    python中的mock接口開發(fā)示例詳解

    這篇文章主要介紹了python中的mock接口開發(fā),Mock接口就是用一些合理的手段構(gòu)造對象去模擬真實(shí)接口,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2022-03-03
  • python實(shí)現(xiàn)Mysql數(shù)據(jù)庫批量新增數(shù)據(jù)的場景分析

    python實(shí)現(xiàn)Mysql數(shù)據(jù)庫批量新增數(shù)據(jù)的場景分析

    這篇文章主要介紹了python實(shí)現(xiàn)Mysql數(shù)據(jù)庫批量新增數(shù)據(jù),本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2022-03-03
  • 基于Python快速處理PDF表格數(shù)據(jù)

    基于Python快速處理PDF表格數(shù)據(jù)

    這篇文章主要介紹了基于Python快速處理PDF表格數(shù)據(jù),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-06-06
  • python語法 range() 序列類型range

    python語法 range() 序列類型range

    這篇文章主要介紹了python語法 range() 序列類型range,range是一種序列類型,range類型用于表示不可變的整數(shù)序列,下面小編整理了簡單內(nèi)容,需要的小伙伴可以參考一下
    2022-01-01
  • 如何使用Python程序完成描述性統(tǒng)計(jì)分析需求

    如何使用Python程序完成描述性統(tǒng)計(jì)分析需求

    這篇文章主要介紹了如何使用Python程序完成描述性統(tǒng)計(jì)分析需求,運(yùn)用制表和分類,圖形以及計(jì)算概括性數(shù)據(jù)來描述數(shù)據(jù)特征的各項(xiàng)活動,需要的朋友可以參考下
    2023-03-03
  • python爬取音頻下載的示例代碼

    python爬取音頻下載的示例代碼

    這篇文章主要介紹了python爬取音頻下載的示例代碼,幫助大家更好的理解和學(xué)習(xí)python爬蟲,感興趣的朋友可以了解下
    2020-10-10
  • numpy 產(chǎn)生隨機(jī)數(shù)的幾種方法

    numpy 產(chǎn)生隨機(jī)數(shù)的幾種方法

    本文主要介紹了numpy 產(chǎn)生隨機(jī)數(shù)的幾種方法,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2023-02-02

最新評論

延川县| 武汉市| 常山县| 麻栗坡县| 襄汾县| 定边县| 诸城市| 长兴县| 东兰县| 高淳县| 宾阳县| 正镶白旗| 富顺县| 密云县| 大安市| 关岭| 南丰县| 九寨沟县| 徐水县| 海城市| 徐汇区| 喀喇沁旗| 永嘉县| 安阳县| 台州市| 清河县| 文化| 晋中市| 南部县| 宣威市| 大冶市| 盖州市| 泽州县| 新疆| 东阳市| 南昌县| 阜新| 榕江县| 淮北市| 九龙坡区| 柏乡县|