CSRF
方法,不講CSRF
講理Django
中關於CSRF
經常使用的一些方法和類Django
中間件爲前提, 看如下內容settings.py => MIDDLEWARE
配置項 => 修改以下MIDDLEWARE = [ ... 'django.middleware.common.CommonMiddleware', # 'django.middleware.csrf.CsrfViewMiddleware', # 註釋掉此行代碼便可 'django.contrib.auth.middleware.AuthenticationMiddleware', ... ]
middleware.py
, 以下# tools/middleware.py from django.utils.deprecation import MiddlewareMixin logger = logging.getLogger(__name__) class CloseCsrfMiddleware(MiddlewareMixin): def process_request(self, request): request.csrf_processing_done = True # csrf處理完畢 logger.info('csrf全局禁用')
在上面兩個方法中,若是你的目的是想全局禁用CSRF驗證,我建議你使用第二個禁用方法,禁的不折不扣的。若是你使用的是第一個方法,你會發現,當你使用admin
、xadmin
或其餘第三方關於認證的插件時,CSRF
機制有時候仍是會蹦出來作怪。爲何?爲何禁了沒有效果?
我在使用xadmin
的時候就遇到這種狀況,分明註釋了django.middleware.csrf.CsrfViewMiddleware
,仍是會提示CSRF
驗證失敗(失敗緣由我就不過多解釋了,不一樣人遇到的狀況不同的,我這裏是由於域名作了二次代理),以登陸爲例,xadmin
部分源碼以下:html
# xadmin/view/website.py ... from django.contrib.auth.views import LoginView as login ... class LoginView(BaseAdminView): ... @never_cache def get(self, request, *args, **kwargs): context = self.get_context() helper = FormHelper() helper.form_tag = False helper.include_media = False context.update({ 'title': self.title, 'helper': helper, 'app_path': request.get_full_path(), REDIRECT_FIELD_NAME: request.get_full_path(), }) defaults = { 'extra_context': context, # 'current_app': self.admin_site.name, 'authentication_form': self.login_form or AdminAuthenticationForm, 'template_name': self.login_template or 'xadmin/views/login.html', } self.update_params(defaults) # return login(request, **defaults) return login.as_view(**defaults)(request) @never_cache def post(self, request, *args, **kwargs): return self.get(request) ...
xadmin
登陸時,後臺方法調用以下:
def post()
=> def get()
=> login.as_view()
; 其中, def post()
、def get()
爲xadmin
下class LoginView()
內的方法;login.as_view()
爲django
原生的登陸驗證類
django
原生的登陸驗證類源碼以下:python
# django/crontrab/auth/view.py class LoginView(SuccessURLAllowedHostsMixin, FormView): ... @method_decorator(sensitive_post_parameters()) @method_decorator(csrf_protect) #### 注意這行 #### @method_decorator(never_cache) def dispatch(self, request, *args, **kwargs): if self.redirect_authenticated_user and self.request.user.is_authenticated: redirect_to = self.get_success_url() if redirect_to == self.request.path: raise ValueError( "Redirection loop for authenticated user detected. Check that " "your LOGIN_REDIRECT_URL doesn't point to a login page." ) return HttpResponseRedirect(redirect_to) return super().dispatch(request, *args, **kwargs)
注意這行代碼@method_decorator(csrf_protect)
在這裏你要知道的是,裝飾器csrf_protect
的做用是進行CSRF
驗證
因此,即便你註釋了django.middleware.csrf.CsrfViewMiddleware
,在這裏通過裝飾器csrf_protect
仍是會再次進行CSRF
驗證。
真相終於大白了。
接下說說,第二種禁用CSRF
方法web
經過查看@csrf_protect
源碼(就不貼上來了)會發現,內部實現是,對class CsrfViewMiddleware
進行了實例化,而後依次調用了中間件中def process_request()
、def process_view()
等方法,其中,CsrfViewMiddleware.process_view()
,是進行CSRF
驗證的邏輯,源碼以下:django
class CsrfViewMiddleware(MiddlewareMixin): ... def process_view(self, request, callback, callback_args, callback_kwargs): # 注意csrf_processing_done變量,這個變量很關鍵 # 這個變量目的是記錄在本次請求中是否已經進行過CSRF校驗 # 若是已經校驗過了,就再也不走下面的驗證邏輯了。 if getattr(request, 'csrf_processing_done', False): return None # 這一步是查看被調用的def view()方法是否加了@csrf_exempt裝飾器 # 若是加了,就再也不走下面的驗證邏輯了。 # Wait until request.META["CSRF_COOKIE"] has been manipulated before # bailing out, so that get_token still works if getattr(callback, 'csrf_exempt', False): return None # 下面就是CSRF的驗證邏輯了 # Assume that anything not defined as 'safe' by RFC7231 needs protection if request.method not in ('GET', 'HEAD', 'OPTIONS', 'TRACE'): if getattr(request, '_dont_enforce_csrf_checks', False): # Mechanism to turn off CSRF checks for test suite. # It comes after the creation of CSRF cookies, so that # everything else continues to work exactly the same # (e.g. cookies are sent, etc.), but before any # branches that call reject(). return self._accept(request) ...
如上所示, 第二種禁用CSRF
方法原理就是, 設置request.csrf_processing_done=True
。
致此,完!cookie