遇到一個問題是,CMDB項目的前端刪除數據要向後端發送 DELETE 請求,須要驗證 CSRF 。可是以前項目一直都是 GET 請求獲取的數據,瀏覽器的 cookies 中沒有 csrftoken 的值,而發送請求以前是從 cookies 中獲取 csrftoken 的值,沒有值也就無法經過驗證。因此就要人爲的設置一下 cookies 中的 csrftoken 值。html
出現這個問題的前提是:前端
一、習慣ajax方式提交POST等請求;ajax
二、習慣從cookie中找csrftoken;django
通常咱們認爲cookie裏的csrftoken是由csrftoken middleware所設置的,事實確實如此,但也不徹底是。貼一段CsrfViewMiddleware的代碼:後端
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 # Set the CSRF cookie even if it's already set, so we renew # the expiry timer. self._set_token(request, response) response.csrf_cookie_set = True return response
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, ) # Set the Vary header since content varies with the CSRF cookie. patch_vary_headers(response, ('Cookie',))
這段代碼的重點在於對CSRF_COOKIE_USED的檢查,若是沒有設置,middleware會直接返回response而不在cookie裏設置csrftoken。瀏覽器
看別人說有三種方法設置CSRF_COOKIE_USED。cookie
1. 手動設置,在view 中添加 session
request.META["CSRF_COOKIE_USED"] = True
2. 手動調用 csrf 中的 get_token(request) 或 rotate_token(request) 方法。dom
from django.middleware.csrf import get_token ,rotate_token def server(request): # get_token(request) // 二者選一 # rotate_token(request) // 此方法每次設置新的cookies return render(request, 'server.html')
3. 在HTML模板中添加 {% csrf_token %}spa
4. 在須要設置cookie的視圖上加裝飾器 ensure_csrf_cookie()
from django.views.decorators.csrf import ensure_csrf_cookie @ensure_csrf_cookie def server(request): return render(request, 'server.html')
親測方法二、三、4有效,都能在cookie中設置csrftoken,可是方法1會報錯,須要本身生成64位的csrftoken。
request.META['CSRF_COOKIE']= 'abc' 配合此行代碼,cookie中的csrftoken設置成了‘abc’.
因此,若是不想在模板中添加{% csrf_token %}標籤,推薦使用方法2中的get_token(request)方法和方法4。
CSRF保護機制的工做原理:https://docs.djangoproject.com/en/1.11/ref/csrf/#how-it-works