Django的 Session 框架
由于存在的限制與安全漏洞绳军,cookies和持續(xù)性會話已經(jīng)成為Web開發(fā)
的隱患矢腻,Django自帶的session框架會幫你搞定這些問題耳贬,你可以用session 框架來存取每個訪問者任意數(shù)據(jù)猎唁, 這些數(shù)據(jù)在服務(wù)器端存儲,并對cookie的收發(fā)進(jìn)行了抽象腐魂。 Cookies只存儲數(shù)據(jù)的哈希會話ID逐纬,而不是數(shù)據(jù)本身,從而避免了大部分的常見cookie問題豁生。
開啟Sessions功能
Sessions 功能是通過一個中間件和一個模型來實現(xiàn)的。 要打開sessions功能育叁,需要以下幾步操作:
確保 MIDDLEWARE_CLASSES 中包含 'django.contrib.sessions.middleware.SessionMiddleware'芍殖。
確保 INSTALLED_APPS 中有 'django.contrib.sessions' (如果你是剛打開這個應(yīng)用,別忘記同步數(shù)據(jù)庫 )
正常情況下龟梦,你無需任何設(shè)置就可以使用session功能窃躲。
在視圖中使用Session
SessionMiddleware 激活后,每個傳給視圖(view)函數(shù)的第一個參數(shù)HttpRequest對象都有一個 session 屬性躁倒,這是一個字典型的對象。 你可以象用普通字典一樣來用它:
# Set a session value:
request.session["fav_color"] = "blue"
# Get a session value -- this could be called in a different view,
# or many requests later (or both):
fav_color = request.session["fav_color"]
# Clear an item from the session:
del request.session["fav_color"]
# Check if the session has a given key:
if "fav_color" in request.session:
其他的映射方法樱溉,如 keys() 和 items() 對 request.session 同樣有效
字典的keys() values() items()方法
字典的items(), keys(), values()都返回一個list
dict = { 1 : 2, 'a' : 'b', 'hello' : 'world' }
dict.values()
['b', 2, 'world']
dict.keys()
['a', 1, 'hello']
dict.items()
[('a', 'b'), (1, 2), ('hello', 'world')]
用正常的字符串作為key來訪問字典 request.session 福贞, 而不是整數(shù)、對象或其它什么的挖帘。Session字典中以下劃線開頭的key值是Django內(nèi)部保留key值
看一個簡單的例子:在用戶發(fā)了一次評論后將has_commented設(shè)置為True。 這是個簡單(但不很安全)的逻族、防止用戶多次評論的方法骄崩。
def post_comment(request):
if request.method != 'POST':
raise Http404('Only POSTs are allowed')
if 'comment' not in request.POST:
raise Http404('Comment not submitted')
if request.session.get('has_commented', False):
return HttpResponse("You've already commented.")
c = comments.Comment(comment=request.POST['comment'])
c.save()
request.session['has_commented'] = True
return HttpResponse('Thanks for your comment!')
一個很簡單的站點登錄視圖(view):在實踐中,這是很爛的用戶登錄方式要拂,稍后討論的認(rèn)證(authentication )框架會幫你以更健壯和有利的方式來處理這些問題。 這些非常簡單的例子只是想讓你知道這一切是如何工作的搏嗡。
def login(request):
if request.method != 'POST':
raise Http404('Only POSTs are allowed')
try:
m = Member.objects.get(username=request.POST['username'])
if m.password == request.POST['password']:
request.session['member_id'] = m.id
return HttpResponseRedirect('/you-are-logged-in/')
except Member.DoesNotExist:
return HttpResponse("Your username and password didn't match.")
def logout(request):
try:
del request.session['member_id']
except KeyError:
pass
return HttpResponse("You're logged out.")
設(shè)置測試Cookies
你不能指望所有的瀏覽器都可以接受cookie拉一。 因此,為了使用方便磅氨,Django提供了一個簡單的方法來測試用戶的瀏覽器是否接受cookie抽碌。 你只需在視圖(view)中調(diào)用 request.session.set_test_cookie()
,并在后續(xù)的視圖(view)左权,而不是當(dāng)前的視圖(view)中檢查 request.session.test_cookie_worked()
def login(request):
# If we submitted the form...
if request.method == 'POST':
# Check that the test cookie worked (we set it below):
if request.session.test_cookie_worked():
# The test cookie worked, so delete it.
request.session.delete_test_cookie()
# In practice, we'd need some logic to check username/password
# here, but since this is an example...
return HttpResponse("You're logged in.")
# The test cookie failed, so display an error message. If this
# were a real site, we'd want to display a friendlier message.
else:
return HttpResponse("Please enable cookies and try again.")
# If we didn't post, send the test cookie along with the login form.
request.session.set_test_cookie()
return render_to_response('foo/login_form.html')
Django Session工作原理:
下面是一些關(guān)于session框架內(nèi)部工作方式的技術(shù)細(xì)節(jié):
session 字典接受任何支持序列化的Python對象痴颊。 參考Python內(nèi)建模塊pickle的文檔以獲取更多信息。
Session 數(shù)據(jù)存在數(shù)據(jù)庫表 django_session 中
Session 數(shù)據(jù)在需要的時候才會讀取锌杀。 如果你從不使用 request.session 糕再, Django不會動相關(guān)數(shù)據(jù)庫表的一根毛。
Django 只在需要的時候才送出cookie突想。 如果你壓根兒就沒有設(shè)置任何會話數(shù)據(jù),它不會 送出會話cookie(除非 SESSION_SAVE_EVERY_REQUEST 設(shè)置為 True )袭灯。
Django session 框架完全而且只能基于cookie绑嘹。 它不會后退到把會話ID編碼在URL中(像某些工具(PHP,JSP)那樣)。這是一個有意而為之的設(shè)計工腋。 把session放在URL中不只是難看,更重要的是這讓你的站點 很容易受到攻擊(通過 Referer header進(jìn)行session ID”竊聽”而實施的攻擊)
如果你還是好奇构挤,閱讀源代碼是最直接辦法惕鼓,django.contrib.sessions 唐础。
在視圖(View)外使用Session:
from django.contrib.sessions.models import Session
s = Session.objects.get(pk='2b1189a188b44ad18c35e113ac6ceead')
s.expire_date
datetime.datetime(2005, 8, 20, 13, 35, 12)
s.session_data
'KGRwMQpTJ19hdXRoX3VzZXJfaWQnCnAyCkkxCnMuMTExY2ZjODI2Yj...'
s.get_decoded() #需要使用get_decoded() 來讀取實際的session數(shù)據(jù)一膨,因為字典存儲為一種特定的編碼格式
{'user_id': 42}
何時保存Session:
缺省的情況下,Django只會在session發(fā)生變化的時候才會存入數(shù)據(jù)庫豹绪,比如說,字典賦值或刪除蝉衣。你可以設(shè)置 SESSION_SAVE_EVERY_REQUEST 為 True 來改變這一缺省行為巷蚪。Django會在每次收到請求的時候保存session,即使沒發(fā)生變化屁柏。
會話cookie只會在創(chuàng)建和修改的時候才會送出淌喻。 但如果 SESSION_SAVE_EVERY_REQUEST 設(shè)置為 True ,會話cookie在每次請求的時候都會送出裸删。 同時,每次會話cookie送出的時候,其 expires 參數(shù)都會更新豌注。
瀏覽器關(guān)閉即失效會話 vs 持久會話:
缺省情況下灯萍, SESSION_EXPIRE_AT_BROWSER_CLOSE 設(shè)置為 False ,這樣齿风,會話cookie可以在用戶瀏覽器中保持有效達(dá) SESSION_COOKIE_AGE 秒(缺省設(shè)置是兩周)绑洛。 如果你不想用戶每次打開瀏覽器都必須重新登陸的話,用這個參數(shù)來幫你脸候。
如果 SESSION_EXPIRE_AT_BROWSER_CLOSE 設(shè)置為 True 绑蔫,當(dāng)瀏覽器關(guān)閉時,Django會使cookie失效携添。
影響cookie行為的設(shè)置:
設(shè)置 | 缺省值 | 描述 |
---|---|---|
SESSION_COOKIE_DOMAIN | 使用會話cookie(session cookies)的站點篓叶。 將它設(shè)成一個字符串,就好象“.example.com” 以用于跨站點(cross-domain)的cookie左敌,或None 以用于單個站點嗦董。 |
None |
SESSION_COOKIE_NAME | 會話中使用的cookie的名字京革。 它可以是任意的字符串 | "sessionid" |
SESSION_COOKIE_SECURE | 是否在session中使用安全cookie。 如果設(shè)置 True , cookie就會標(biāo)記為安全咬扇, 這意味著cookie只會通過HTTPS來傳輸廊勃。 | False |