2012-07-13 77 views
1

一個CSRF令牌,我從第三方服務器期待POST。我知道我需要使用@csrf_exempt修飾器來允許來自第三方服務器的帖子。我在Ubuntu 12.04上使用Django 1.4和Python 2.7。使用@csrf_exempt並創造了同樣的觀點

現在,我的視圖將生成一個未綁定的表單,其中將包含用戶填充的字段以及包含來自原始POST的信息的隱藏字段。所以,第一個POST將啓動第二個POST

第二個POST將從我的服務器發送到我的服務器上的另一個視圖。我試圖找出如何爲我的表單生成一個CSRF令牌。

我正在試圖完成我在documentation中讀到的內容。

我的代碼views.py:

from django.core.context_processors import csrf 
from django.shortcuts import render_to_response 
from gateway_interface.post_handling import PostHandling 

@csrf_exempt 
def requestNewPaymentInfo(request): 

    c = {} 
    c.update(csrf(request)) 

    # Gather information posted 
    if (request.method == "POST"): 
     # Create the initialization dictionary based on POST values 
     postHandling = PostHandling() 
     post_dict = postHandling.createDictionary(request) 

     # Create the form 
     form = addPaymentForm(initial = post_dict) 

     return render_to_response('requestNewPaymentInfo.html', { 'form' : form }, c) 

你怎麼在模板上現在怎麼辦?!?再次,從文件,我想我應該做到以下幾點:

<form action="/addPayment/" method="post"> 
    {% csrf_token %} 
</form> 

我通過從第三方服務器做一個POST進行測試。有時我會看到完全生成的表單,其中看起來有效的代碼爲CSRF

有時候,我看到一個失敗,看起來像這樣:

Django Version: 1.4 
Python Version: 2.7.3 
Installed Applications: 
('django.contrib.auth', 
'django.contrib.contenttypes', 
'django.contrib.sessions', 
'django.contrib.sites', 
'django.contrib.messages', 
'django.contrib.staticfiles', 
'django.contrib.admin', 
'gateway_interface') 
Installed Middleware: 
('django.middleware.common.CommonMiddleware', 
'django.contrib.sessions.middleware.SessionMiddleware', 
'django.middleware.csrf.CsrfViewMiddleware', 
'django.contrib.auth.middleware.AuthenticationMiddleware', 
'django.contrib.messages.middleware.MessageMiddleware') 


Traceback: 
File "/usr/local/lib/python2.7/dist-packages/django/core/handlers/base.py" in get_response 
    111.       response = callback(request, *callback_args, **callback_kwargs) 
File "/usr/local/lib/python2.7/dist-packages/django/views/decorators/csrf.py" in wrapped_view 
    77.   return view_func(*args, **kwargs) 
File "/home/tokeniz/tokeniz/gateway_interface/views.py" in requestNewPaymentInfo 
    64.   return render_to_response('requestNewPaymentInfo.html', { 'form' : form }, c) 
File "/usr/local/lib/python2.7/dist-packages/django/shortcuts/__init__.py" in render_to_response 
    20.  return HttpResponse(loader.render_to_string(*args, **kwargs), **httpresponse_kwargs) 
File "/usr/local/lib/python2.7/dist-packages/django/template/loader.py" in render_to_string 
    178.   context_instance.pop() 

Exception Type: TypeError at /requestNewPaymentInfo/ 
Exception Value: pop expected at least 1 arguments, got 0 

然後,我將最終得到這個錯誤:當我收到CSRF verification failed錯誤

Forbidden (403) 
CSRF verification failed. Request aborted. 

我會繼續得到這種錯誤,直到我清除cookie並重新開始。

誰能告訴我我做錯了什麼?我可以看到它與我如何生成CSRF令牌有關。我不明白這個過程如何基於文檔中的內容工作。在我看來,什麼是c?一個空字典,我填充信息並傳遞到render_to_response。好的,但模板中如何使用它?

如果我的模板有這樣的事情:

<form action="/addPayment/" method="post"> 
    {% c.csrf_token %} 
</form> 

如果不是,爲什麼? Django如何知道這個c包含CSRF標記?

任何幫助將不勝感激。

回答

4

解決您的問題,讓我可以澄清一些事情。簡而言之

Django的模板系統的工作原理與兩段數據:背景模板

當你把一個變量在模板文件中顯示,像{{ foo }},Django是要往裏相應上下文實例,一個dict類固醇,發現該變量的值。

現在到render_to_response,你傳遞給它的第二個參數dict本質上就是你想放在模板上下文中的數據,所以它可以爲你提供。第三個參數是一個Context實例,而不是數據本身,當您需要定製事物時它可能很有用。

好了,讓我們看看你的榜樣,

return render_to_response('requestNewPaymentInfo.html', { 'form' : form }, c) 

在這裏,你犯了一個錯誤的閱讀文檔例子,你把c作爲上下文實例,沒有上下文數據,因此您的令牌沒甚至沒有把它放到模板上,你得到了所有那些django期待Context對象的奇怪錯誤,但只有字典。

因此,要解決,你只需要通過模板裏面的數據CSRF令牌:

c.update({'form': form}) 
return render_to_response('requestNewPaymentInfo.html', c) 

而且在模板中:

{% csrf_token %} 

我建議閱讀template system explanation for programmers,它寫的很好。