postman模擬登錄出了這個錯誤,其實看標題就知道大概是怎么回事,網上大概找了辦法,也沒說到位,所以干脆自己找源碼了.
問題很明顯就是出在 CSRF 上,理所當然去查看 CsrfViewMiddleware 中間件:
1 class CsrfViewMiddleware(object): 2 3 def _accept(self, request): 4 5 request.csrf_processing_done = True 6 return None 7 8 def _reject(self, request, reason): 9 logger.warning('Forbidden (%s): %s', reason, request.path, 10 extra={ 11 'status_code': 403, 12 'request': request, 13 } 14 ) 15 return _get_failure_view()(request, reason=reason) 16 17 def process_view(self, request, callback, callback_args, callback_kwargs): 18 19 if getattr(request, 'csrf_processing_done', False): 20 return None 21 22 try: 23 csrf_token = _sanitize_token( 24 request.COOKIES[settings.CSRF_COOKIE_NAME]) 25 request.META['CSRF_COOKIE'] = csrf_token 26 except KeyError: 27 csrf_token = None 28 29 request.META["CSRF_COOKIE"] = _get_new_csrf_key() 30 31 return None 32 e that anything not defined as 'safe' by RFC2616 needs protection 33 if request.method not in ('GET', 'HEAD', 'OPTIONS', 'TRACE'): 34 if getattr(request, '_dont_enforce_csrf_checks', False): 35 return self._accept(request) 36 37 if request.is_secure(): 38 referer = force_text( 39 request.META.get('HTTP_REFERER'), 40 strings_only=True, 41 errors='replace' 42 ) 43 if referer is None: 44 return self._reject(request, REASON_NO_REFERER) # 問題就出在這里 45 46 good_referer = 'https://%s/' % request.get_host() 47 if not same_origin(referer, good_referer): 48 reason = REASON_BAD_REFERER % (referer, good_referer) 49 return self._reject(request, reason) 50 51 if csrf_token is None: 52 return self._reject(request, REASON_NO_CSRF_COOKIE) 53 request_csrf_token = "" 54 if request.method == "POST": 55 try: 56 request_csrf_token = request.POST.get('csrfmiddlewaretoken', '') 57 except IOError: 58 pass 59 60 if request_csrf_token == "": 61 request_csrf_token = request.META.get('HTTP_X_CSRFTOKEN', '') 62 63 if not constant_time_compare(request_csrf_token, csrf_token): 64 return self._reject(request, REASON_BAD_TOKEN) 65 66 return self._accept(request)
首先在文件里面搜索報錯的信息字符串,找到這個:
REASON_NO_REFERER = "Referer checking failed - no Referer."
然后搜索 REASON_NO_REFERER 就會找到上面的那一段代碼中出錯的位置.(為什么寫這些東西,因為我有個同學就是從來都不會找出錯原因,方法有時候比結論更重要)
然后代碼里面說的很清楚了, referer = request.META.get('HTTP_REFERER')
這就說明請求頭里面沒有 REFERER這個信息,都知道的,Django會把自定義的請求頭大寫並在前面添加 HTTP_ ,所以在postman的header里面添加這個 referer 字段就好了.
注意,referer的格式是 https://www.domain.com/. 后面有個點
然后就OK了
多說兩句,看看人家django多貼心,如果是post請求的話,會嘗試從兩個地方獲取csrftoken,請求體里面可以放,就算忘了放,還會從請求頭里面拿(54行 - 64行)