Django使用csrf時cookie沒有csrf_token的問題

今天被這個問題困擾了一上午芥备,理清以后發(fā)覺正常情況下是不會遇到這個問題的不见。
遇到這個問題的前提是什么呢研儒?

  1. 習(xí)慣ajax方式提交POST請求
  2. 習(xí)慣從cookie里找csrftoken

這次是在一個新建的project里遇到的這個問題单寂,舊project的base foundation都比較完善系吩,所以才沒有特別注意csrftoken的來源問題徘郭。

一般我們認(rèn)為cookie里的csrftoken是由csrftoken middleware所設(shè)置的靠益,事實確實如此,但也不完全是残揉。貼一段CsrfViewMiddleware的代碼:

def process_response(self, request, response):
        if getattr(response, 'csrf_processing_done', False):
            return response

        # If CSRF_COOKIE is unset, then CsrfViewMiddleware.process_view was
        # never called, probably because a request middleware returned a response
        # (for example, contrib.auth redirecting to a login page).
        if request.META.get("CSRF_COOKIE") is None:
            return response

        # 重點(diǎn)在這里
        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.
        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
                            )
        # Content varies with the CSRF cookie, so set the Vary header.
        patch_vary_headers(response, ('Cookie',))
        response.csrf_processing_done = True
        return response

這段代碼的重點(diǎn)在于對CSRF_COOKIE_USED的檢查捆毫,如果沒有設(shè)置,middleware會直接返回response而不在cookie里設(shè)置csrftoken冲甘。
而CSRF_COOKIE_USED是在哪設(shè)置的呢绩卤?有幾種途徑:

  1. 手動設(shè)置。在你的view里添加request.META["CSRF_COOKIE_USED"] = True
  2. 手動調(diào)用csrf middleware的get_token(request)rotate_token(request)方法
  3. 在你的html模板里添加 {% csrf_token %}

我今天的問題就在于第三種途徑江醇。舊project里是有添加的濒憋,而新project里沒有,所以導(dǎo)致了我的問題陶夜。

官方文檔建議在每一個form里都添加這樣的標(biāo)簽凛驮,這樣能夠在提交表單時自動將csrftoken添加進(jìn)請求里。
對于ajax post文檔也指出從cookie拿會比較方便条辟。

那這個標(biāo)簽具體做了什么呢黔夭?
使用這個標(biāo)簽會讓django模板引擎在這里插入一個隱藏的input用來存放csrftoken。在django.template.defaulttags里我們可以找到一個叫CsrfTokenNode的類羽嫡,它的render方法檢查了context里的csrf_token本姥。

def render(self, context):
        csrf_token = context.get('csrf_token', None)
        if csrf_token:
            if csrf_token == 'NOTPROVIDED':
                return format_html("")
            else:
                return format_html("<input type='hidden' name='csrfmiddlewaretoken' value='{}' />", csrf_token)
        else:
            ...

context中的csrf_token是一個django.template.context_processors.csrf的實例,他本身就等同于自己的_get_val()杭棵,只不過是在每次用到自己的時候才調(diào)用該方法獲得返回值婚惫。(這部分也是值得一寫的內(nèi)容)

所以可以看到在上面的render方法中的第二行,有一次對csrf_token的判斷魂爪,正是在這里調(diào)用了_get_val先舷,在_get_val中調(diào)用了get_token,get_token會從request里取CSRF_COOKIE滓侍,CSRF_COOKIE又是由middleware在process_view中提供的蒋川,所以最終會讓CsrfViewMiddleware在process_response里把csrftoken添加進(jìn)cookie里,也就可以在前端拿到cookie了撩笆。

總結(jié)一下捺球,這之間發(fā)生的事情就是:

  1. html文件添加{% csrf_token %}標(biāo)簽
  2. CsrfViewMiddleware在process_view時向request添加CSRF_COOKIE
  3. 渲染模板檢測到該標(biāo)簽街图,在渲染時添加CsrfTokenNode類
  4. CsrfTokenNode的渲染方法檢查csrf_token
  5. 對csrf_token進(jìn)行判斷時調(diào)用get_token
  6. get_token檢查request中的CSRF_COOKIE,并設(shè)置CSRF_COOKIE_USED為True
  7. CsrfViewMiddleware在process_response設(shè)置cookie中的csrftoken

這樣前端就能看到cookie了懒构。

以上就是對這個問題的解決辦法的記錄餐济。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市胆剧,隨后出現(xiàn)的幾起案子絮姆,更是在濱河造成了極大的恐慌,老刑警劉巖秩霍,帶你破解...
    沈念sama閱讀 218,755評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件篙悯,死亡現(xiàn)場離奇詭異,居然都是意外死亡铃绒,警方通過查閱死者的電腦和手機(jī)鸽照,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,305評論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來颠悬,“玉大人矮燎,你說我怎么就攤上這事∨獍” “怎么了诞外?”我有些...
    開封第一講書人閱讀 165,138評論 0 355
  • 文/不壞的土叔 我叫張陵,是天一觀的道長灾票。 經(jīng)常有香客問我峡谊,道長,這世上最難降的妖魔是什么刊苍? 我笑而不...
    開封第一講書人閱讀 58,791評論 1 295
  • 正文 為了忘掉前任既们,我火速辦了婚禮,結(jié)果婚禮上正什,老公的妹妹穿的比我還像新娘啥纸。我一直安慰自己,他們只是感情好埠忘,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,794評論 6 392
  • 文/花漫 我一把揭開白布脾拆。 她就那樣靜靜地躺著,像睡著了一般莹妒。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上绰上,一...
    開封第一講書人閱讀 51,631評論 1 305
  • 那天旨怠,我揣著相機(jī)與錄音,去河邊找鬼蜈块。 笑死鉴腻,一個胖子當(dāng)著我的面吹牛迷扇,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播爽哎,決...
    沈念sama閱讀 40,362評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼蜓席,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了课锌?” 一聲冷哼從身側(cè)響起厨内,我...
    開封第一講書人閱讀 39,264評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎渺贤,沒想到半個月后雏胃,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,724評論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡志鞍,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,900評論 3 336
  • 正文 我和宋清朗相戀三年瞭亮,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片固棚。...
    茶點(diǎn)故事閱讀 40,040評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡统翩,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出此洲,到底是詐尸還是另有隱情唆缴,我是刑警寧澤,帶...
    沈念sama閱讀 35,742評論 5 346
  • 正文 年R本政府宣布黍翎,位于F島的核電站面徽,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏匣掸。R本人自食惡果不足惜趟紊,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,364評論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望碰酝。 院中可真熱鬧霎匈,春花似錦、人聲如沸送爸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,944評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽袭厂。三九已至墨吓,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間纹磺,已是汗流浹背帖烘。 一陣腳步聲響...
    開封第一講書人閱讀 33,060評論 1 270
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留橄杨,地道東北人秘症。 一個月前我還...
    沈念sama閱讀 48,247評論 3 371
  • 正文 我出身青樓照卦,卻偏偏與公主長得像,于是被迫代替她去往敵國和親乡摹。 傳聞我的和親對象是個殘疾皇子役耕,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,979評論 2 355

推薦閱讀更多精彩內(nèi)容