前戲
我們在通路一些網站的時候,如果沒有登入就會跳轉到登入頁面,如果是登入了,才會讓我們通路,那伺服器是怎麼知道我們有沒有登入呢?這就涉及到了Cookie,大家都知道HTTP的特點,無狀态。也就是浏覽器發送到伺服器的每個請求都是沒有關系的。這時候就要給伺服器設定一個Cookie,下次浏覽器請求的時候,攜帶這個Cookie,如果有攜帶,那伺服器就認為是登入的,如果沒有攜帶或錯誤,那浏覽器就跳轉到登入頁面。
什麼是Cookie呢?
Cookie是指一小段資訊,它是伺服器發送出來存儲在浏覽器上的一組組鍵值對,下次通路伺服器時浏覽器會自動攜帶這些鍵值對。Cookie的工作原理是由伺服器産生内容,浏覽器收到請求後儲存在本地,當浏覽器再次通路時,浏覽器會自動帶上Cookie,這樣伺服器就能通過Cookie判斷目前使用者是哪個了
Cookie初識
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form action="{{ request.get_full_path }}" method="post">
{% csrf_token %}
使用者名:
<input type="text" name="username">
密碼:
<input type="text" name="pwd">
<input type="submit" value="送出">
</form>
</body>
</html>
login.html
我們寫三個視圖函數,login,home和index
from django.shortcuts import render,redirect,HttpResponse
from appTest01 import models
# Create your views here.
def login(request):
if request.method == 'POST':
user = request.POST.get('username')
password = request.POST.get('pwd')
if models.Person.objects.filter(name=user, pwd= password):
return redirect('/index/')
return render(request,'login.html')
def index(request):
return HttpResponse('index')
def home(request):
return HttpResponse('home')
上面這樣的寫法,我們可以直接通過路徑通路對應的頁面,不需要登入,當然不符合我們的需求,那我們給加上Cookie
from django.shortcuts import render,redirect,HttpResponse
from appTest01 import models
# Create your views here.
def login(request):
if request.method == 'POST':
user = request.POST.get('username')
password = request.POST.get('pwd')
if models.Person.objects.filter(name=user, pwd= password):
ret = redirect('/index/')
ret.set_cookie('is_login','yes')
return ret
return render(request,'login.html')
def index(request):
print(request.COOKIES,type(request.COOKIES)) 檢視cookie
return HttpResponse('index')
def home(request):
return HttpResponse('home')
我們使用set_cookie()來設定Cookie,然後我們輸入賬号密碼去登入,檢視cookie
我們可以使用 request.COOKIES來檢視cookie,
request.COOKIES,type(request.COOKIES)
結果:
{'csrftoken': 'pB5vZxQOwWnvNyw13S0ImpbInxOpnIV0BsAcE31hCHLOP3EIMM8veLpxIlcRBYIg', 'is_login': 'yes'} <class 'dict'>
既然它是一個字典類型的,我們就可以拿到cookie,然後在進行一個判斷,在來改寫視圖函數
from django.shortcuts import render,redirect,HttpResponse
from appTest01 import models
# Create your views here.
def login(request):
if request.method == 'POST':
user = request.POST.get('username')
password = request.POST.get('pwd')
if models.Person.objects.filter(name=user, pwd = password):
ret = redirect('/index/')
ret.set_cookie('is_login','yes')
return ret
return render(request,'login.html')
def index(request):
if request.COOKIES.get('is_login') == 'yes': # 擷取我們設定的Cookie
return HttpResponse('index')
return redirect('/login/')
def home(request):
if request.COOKIES.get('is_login') == 'yes':
return HttpResponse('home')
return redirect('/login/')
上面代碼我們就實作了我們的需求,如果登入成功,可以通路index和home頁面,如果沒有登入,則傳回login頁面,那試想一下,以後我們的項目頁面有幾百個,難道要給每個頁面都要寫判斷嗎?這樣肯定是不行的,我們可以用裝飾器來實作這種需求,代碼如下
from django.shortcuts import render, redirect, HttpResponse
from appTest01 import models
# Create your views here.
def login_cookie(f):
def inner(request, *args, **kwargs):
if request.COOKIES.get('is_login') == 'yes': # 擷取我們設定的Cookie,如果通過,執行被裝飾的函數
res = f(request, *args, **kwargs)
return res
return redirect('/login/')
return inner
def login(request):
if request.method == 'POST':
user = request.POST.get('username')
password = request.POST.get('pwd')
if models.Person.objects.filter(name=user, pwd=password):
ret = redirect('/index/')
ret.set_cookie('is_login', 'yes')
return ret
return render(request, 'login.html')
@login_cookie
def index(request):
return HttpResponse('index')
@login_cookie
def home(request):
return HttpResponse('home')
但是這樣又有個問題,如果我們沒有登入通路home頁面,它會跳轉到登入頁面,我們正确登入之後傳回到了index頁面,這肯定不是我們需要的效果,因為我們在login函數裡已經寫死了,登入成功之後傳回的是index頁面,我們來看下京東沒登入時點選“我的京東”是怎樣處理的
我們可以看到,京東在登入頁面後面加了個參數,然後登入成功之後,直接跳轉到後面的那個參數頁面了,那我們在來修改我們的代碼
from django.shortcuts import render, redirect, HttpResponse
from appTest01 import models
# Create your views here.
def login_cookie(f):
def inner(request, *args, **kwargs):
current_url = request.path_info # 擷取位址中?後面的參數
print('current_url為:', current_url)
if request.COOKIES.get('is_login') == 'yes':
res = f(request, *args, **kwargs)
return res
return redirect('/login/?returnurl={}'.format(current_url)) # 拼接url路徑
return inner
def login(request):
if request.method == 'POST':
user = request.POST.get('username')
password = request.POST.get('pwd')
if models.Person.objects.filter(name=user, pwd=password):
url_parameter = request.GET.get('returnurl') # 擷取目前路徑裡的returnurl參數
ret = redirect(url_parameter) # 傳回到returnurl頁面
ret.set_cookie('is_login', 'yes')
return ret
return render(request, 'login.html')
@login_cookie
def index(request):
return HttpResponse('index')
@login_cookie
def home(request):
return HttpResponse('home')
結果:
如果你在未登入狀态下通路home頁面,current_url就為/home/
如果你在未登入狀态下通路index頁面,current_url就為/index/
那麼問題又來了,如果我們直接通路login頁面,登入成功則會報錯,這是因為目前的 url_parameter 參數為空,隻需要修改login函數裡的東西就可以了
def login(request):
if request.method == 'POST':
user = request.POST.get('username')
password = request.POST.get('pwd')
if models.Person.objects.filter(name=user, pwd=password):
url_parameter = request.GET.get('returnurl') # 擷取目前路徑裡的returnurl參數
if url_parameter: # 如果有值
ret = redirect(url_parameter) # 傳回到returnurl頁面
else: # 如果為空
ret = redirect('/home/')
ret.set_cookie('is_login', 'yes')
return ret
return render(request, 'login.html')
設定和擷取Cookie
在上面的例子中,我們是使用 set_cookie()來進行設定Cookie,還有另一種方式
rep = HttpResponse(...)
rep = render(request, ...)
rep.set_cookie(key,value,...)
rep.set_signed_cookie(key,value,salt='加密鹽',...)
擷取Cookie就不能使用request.COOKIES[’key‘]或者request.COOKIES.get('key')的方法擷取了,要使用如下的方法擷取
request.get_signed_cookie('key', default=RAISE_ERROR, salt='', max_age=None)
get_signed_cookie方法的參數:
- default: 預設值
- salt: 加密鹽
- max_age: 背景控制過期時間
删除Cookie
删除Cookie使用delete_cookie('key')
def loginout(request):
res = redirect('/login/')
res.delete_cookie('is_login') # 删除我們設定的is_login的cookie
return res
Cookie的其他參數
- key,鍵
- value='' 值
- max_age=xx 逾時時間,xx為一個int型的,機關為秒,如xx=60,則cookie的有效期為60秒
- path='/', Cookie生效的路徑,/ 表示根路徑,特殊的:根路徑的cookie可以被任何url的頁面通路
- domain=None, Cookie生效的域名
- secure=False, https傳輸
- httponly=False 隻能http協定傳輸,無法被JavaScript擷取(不是絕對,底層抓包可以擷取到也可以被覆寫)
Session
Cookie雖然在一定程度上解決了“保持狀态”的需求,但是由于Cookie本身最大支援4096位元組,以及Cookie本身儲存在用戶端,可能被攔截或竊取,是以就需要有一種新的東西,它能支援更多的位元組,并且他儲存在伺服器,有較高的安全性。這就是Session。
問題來了,基于HTTP協定的無狀态特征,伺服器根本就不知道通路者是“誰”。那麼上述的Cookie就起到橋接的作用。
我們可以給每個用戶端的Cookie配置設定一個唯一的id,這樣使用者在通路時,通過Cookie,伺服器就知道來的人是“誰”。然後我們再根據不同的Cookie的id,在伺服器上儲存一段時間的私密資料,如“賬号密碼”等等。
設定session
我們隻需要把上面設定cookie和設定session的代碼改下11,30,48行就可以了
1 from django.shortcuts import render, redirect, HttpResponse
2 from appTest01 import models
3
4
5 # Create your views here.
6
7 def login_cookie(f):
8 def inner(request, *args, **kwargs):
9 current_url = request.path_info # 擷取位址中?後面的參數
10 print('current_url為:', current_url)
11 # if request.COOKIES.get('is_login') == 'yes':
12 if request.session.get('is_login') == 'yes': # 擷取session
13 res = f(request, *args, **kwargs)
14 return res
15 return redirect('/login/?returnurl={}'.format(current_url)) # 拼接url路徑
16
17 return inner
18
19
20 def login(request):
21 if request.method == 'POST':
22 user = request.POST.get('username')
23 password = request.POST.get('pwd')
24 if models.Person.objects.filter(name=user, age=password):
25 url_parameter = request.GET.get('returnurl') # 擷取目前路徑裡的returnurl參數
26 if url_parameter: # 如果有值
27 ret = redirect(url_parameter) # 傳回到returnurl頁面
28 else: # 如果為空
29 ret = redirect('/home/')
30 # ret.set_cookie('is_login', 'yes',max_age=5)
31 request.session['is_login']='yes' # 設定session
32 return ret
33 return render(request, 'login.html')
34
35
36 @login_cookie
37 def index(request):
38 return render(request, 'index.html')
39
40
41 @login_cookie
42 def home(request):
43 return HttpResponse('home')
44
45
46 def loginout(request):
47 res = redirect('/login/')
48 # res.delete_cookie('is_login') # 删除我們設定的is_login的cookie
49 request.session.delete() # 删除session
50 return res
session會預設存在django_session這張表裡
你去浏覽器檢視cookie會發現,這時浏覽器儲存的key不在是is_login了,而是sessionid,value也不在是yes了,而是資料庫裡存的session_key,當浏覽器在次發請求時,Django會去django_session表裡查詢有沒有對應的這個value,如果有,則認為登入過
session的其他方法
# 擷取、設定、删除Session中資料
request.session['k1'] # 擷取key,找不到會報錯
request.session.get('k1',None) # 擷取key,找不到為None
request.session['k1'] = 123 # 設定session
request.session.setdefault('k1',123) # 設定,如果存在k1則不設定
del request.session['k1'] # 删除k1的session
# 所有 鍵、值、鍵值對
request.session.keys() # 擷取所有的key
request.session.values() # 擷取所有的value
request.session.items() # 擷取所有的key和value
request.session.iterkeys() # 生成器類型的key
request.session.itervalues() # 生成器類型的value
request.session.iteritems()
# 會話session的key
request.session.session_key # 擷取資料庫裡存的那個session_key的值
# 将所有Session失效日期小于目前日期的資料删除
request.session.clear_expired()
# 檢查會話session的key在資料庫中是否存在
request.session.exists("session_key") # 布爾值,存在傳回True
# 删除目前會話的所有Session資料
request.session.delete() # 浏覽器裡的sessionid還存在,隻是删除了資料庫裡的資料
# 删除目前的會話資料并删除會話的Cookie。
request.session.flush()
這用于確定前面的會話資料不可以再次被使用者的浏覽器通路
例如,django.contrib.auth.logout() 函數中就會調用它。
# 設定會話Session和Cookie的逾時時間
request.session.set_expiry(value)
* 如果value是個整數,session會在些秒數後失效。
* 如果value是個datatime或timedelta,session就會在這個時間後失效。
* 如果value是0,使用者關閉浏覽器session就會失效。
* 如果value是None,session會依賴全局session失效政策。
session配置
from django.conf import global_settings
1. 資料庫Session
SESSION_ENGINE = 'django.contrib.sessions.backends.db' # 引擎(預設資料庫)
2. 緩存Session
SESSION_ENGINE = 'django.contrib.sessions.backends.cache' # 引擎
SESSION_CACHE_ALIAS = 'default' # 使用的緩存别名(預設記憶體緩存,也可以是memcache),此處别名依賴緩存的設定
3. 檔案Session
SESSION_ENGINE = 'django.contrib.sessions.backends.file' # 引擎
SESSION_FILE_PATH = None # 緩存檔案路徑,如果為None,則使用tempfile子產品擷取一個臨時位址tempfile.gettempdir()
4. 緩存+資料庫
SESSION_ENGINE = 'django.contrib.sessions.backends.cached_db' # 引擎
5. 加密Cookie Session
SESSION_ENGINE = 'django.contrib.sessions.backends.signed_cookies' # 引擎
其他公用設定項:
SESSION_COOKIE_NAME = "sessionid" # Session的cookie儲存在浏覽器上時的key,即:sessionid=随機字元串(預設)
SESSION_COOKIE_PATH = "/" # Session的cookie儲存的路徑(預設)
SESSION_COOKIE_DOMAIN = None # Session的cookie儲存的域名(預設)
SESSION_COOKIE_SECURE = False # 是否Https傳輸cookie(預設)
SESSION_COOKIE_HTTPONLY = True # 是否Session的cookie隻支援http傳輸(預設)
SESSION_COOKIE_AGE = 1209600 # Session的cookie失效日期(2周)(預設)
SESSION_EXPIRE_AT_BROWSER_CLOSE = False # 是否關閉浏覽器使得Session過期(預設)
SESSION_SAVE_EVERY_REQUEST = False # 是否每次請求都儲存Session,預設修改之後才儲存(預設)
總結:
1. cookie
1. cookie是什麼?
儲存在浏覽器上一組組鍵值對
2. 為什麼要有cookie?
http協定是無狀态,每次請求都是無關聯的,沒有辦法儲存狀态。
使用cookie儲存狀态。
3. django的操作cookie
3.1. 設定cookie
ret = HttpResponse('xxx')
ret.set_cookie(key,value,max_age=5)
ret.set_signed_cookie(key,value,max_age=5,salt='xxx')
3.2. 擷取cookie
request.COOKIES['is_login']
request.COOKIES.get('is_login')
request.get_signed_cookie(key,salt='xxx',default='')
3.3. 删除cookie
ret.delete_cookie(key)
2. session
1. session是什麼?
儲存在伺服器上一組組鍵值對,依賴cookie
2. 為什麼要用session?
2.1. cookie儲存在浏覽器上 不安全
2.2. cookie的長度受到限制
3. django中操作session
3.1. 設定session
request.session[key] = value
request.session.setdefault(key,value)
3.2. 擷取session
request.session[key]
request.session.get(key)
3.3. 删除session
del request.session[key] ——》删除某一個鍵值對
request.session.delete() ——》 删除該使用者的所有的session資料,不删除cookie
request.session.flush() ——》 删除該使用者的所有的session資料,删除cookie
4. 設定逾時時間
request.session.set_expiry()
5. 清除所有過期的session
request.session.clear_expired()
轉載于:https://www.cnblogs.com/zouzou-busy/p/11241155.html