在JavaWeb中,客戶向某一服務器發出第一個請求開始,會話就開始了,直到客戶關閉了瀏覽器會話結束。在一個會話的多個請求中共享數據,這就是會話跟蹤技術。html
例如在一個會話中的請求以下(請求銀行主頁):前端
在上面會話中,當前用戶信息必須在這個會話中共享的,由於登陸的是張三,那麼在轉帳和還款時必定是相對張三的轉帳和還款!這就說明咱們必須在一個會話過程當中有共享數據的能力。python
在程序中,會話跟蹤是很重要的事情。理論上,一個用戶的全部請求都應該屬於同一個會話,而另外一個用戶的全部請求則該屬於另外一個會話,兩者不能混淆。例如,用戶A在超市購買的任何商品都應該放在A的購物車內,不管是用戶A何時購買的,這都是屬於同一個會話,不能放在用戶B或者用戶C的購物車內,這不屬於同一個會話。mysql
咱們知道HTTP協議是無狀態協議,也就是說每一個請求都會獨立的! 沒法記錄前一次請求的狀態。可是HTTP協議中可使用Cookie來完成會話跟蹤技術!web
在JavaWeb開發中,使用session來完成會話跟蹤,session底層依賴Cookie技術。正則表達式
cookie是經過在客戶端記錄信息肯定用戶身份,Session是經過在服務端記錄信息肯定用戶身份。算法
上圖很明顯的展現了Django的session和cookie的實現原理。服務器會生成兩份相同的cookie字符串,一份保存在本地,一份發向請求的瀏覽器。瀏覽器將會受到的cookie字符串保存下來,當下次再發請求時,會將信息與這段cookie一同發送到服務器,服務器獲得這段cookie會與本地保存的那份判斷是否相同,若是相同就表示用戶已經登陸成功,保存用戶登陸成功的狀態。Django的session保存在數據庫中的數據至關於一個大字典,key爲cookie的字符串,value還是一個字典,字典的key和value爲用戶設置的相關信息,這樣就能夠方便的存取session裏面的信息。sql
HTTP被設計爲「無狀態」,每次請求都處於相同的空間中。在一次請求和下一次狀況之間沒有任何狀態保持,咱們沒法根據請求的任何方面(IP地址,用戶代理等)來識別同一人的連續請求,因此HTTP協議不具有保存以前發送過的請求或響應的功能。數據庫
協議對於事務處理沒有記憶能力,對同一個URL請求沒有上下文關係,每次的請求都是獨立的,它的執行狀況和結果與以前的請求和以後的請求時無直接關係的。它不會受前面的請求應答狀況直接影響,也不會直接影響後面的請求應答狀況。服務器中沒有保存客戶端的狀態,客戶端必須每次帶上本身的狀態去請求服務器。django
若是說每一一種機制用來處理無狀態,那麼就須要花費時間不停的進行身份驗證,正是這樣,HTTP引入了session和cookie,即保持了HTTP的無狀態性,也使得HTTP的應用稱爲有狀態的。
Cookie翻譯成中文是小甜點,小餅乾的意思。在HTTP中它表示服務器送給客戶端瀏覽器的小甜點。其實Cookie是 key-value 結構,相似於一個python中的字典。隨着服務器端的響應發送給客戶端瀏覽器。而後客戶端瀏覽器會把Cookie保存起來,當下一次再訪問服務器時把Cookie再發送給服務器。
注意:cookie不能跨瀏覽器的,cookie中不能存在中文
Cookie是由服務器建立,而後經過響應發送給客戶端的一個鍵值對。客戶端會保存Cookie,並會標註出Cookie的來源(哪一個服務器的Cookie)。當客戶端向服務器發出請求時會把全部這個服務器Cookie包含在請求中發送給服務器,這樣服務器就能夠識別客戶端!
咱們使用Chrome瀏覽器,打開開發者工具。
咱們舉個簡單的例子。
代碼以下:
modes.py
from django.db import models # Create your models here. class UserInfo(models.Model): user = models.CharField(max_length=32) pwd = models.CharField(max_length=32)
咱們給UserInfo表中插入一條記錄,好比用戶名和密碼都是123(方便起見)。
views.py
from django.shortcuts import render, HttpResponse,redirect # Create your views here. from cookie_demo.models import UserInfo def index(request): if request.method == 'POST': user = request.POST.get('user') pwd = request.POST.get('pwd') user = UserInfo.objects.filter(user=user, pwd=pwd).first() if user: # 登陸成功 ''' :return HttpResponse() :return render() :return redirect() 這三個都返回的是HTTPResponse,只不過render 和redirect 將其封裝了 ''' response = HttpResponse("OK") response.set_cookie('is_login', True) return response else: pass return render(request, 'cookie/index.html')
index.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>index</title> </head> <body> <form action="" method="post"> {% csrf_token %} <p>用戶名:<input type="text" name="user"></p> <p>密碼:<input type="password" name="pwd"></p> <input type="submit" value="submit"> </form> </body> </html>
咱們輸入一個正確的用戶名和密碼,咱們在前端cookie能夠看到其信息:
在響應頭,咱們也能夠看到其信息:
上面的數據只是HTTP的Cookie規範,可是在瀏覽器大戰的今天,一些瀏覽器爲了戰勝對手,爲了展現本身的能力起見,可能對Cookie規範「擴展」了一些,例如每一個Cookie的大小爲8KB,最多可保存500個Cookie等!但也不會出現將你的硬盤佔滿的可能!
注意:不一樣瀏覽器之間是不共享Cookie的,也就是說在你使用IE訪問服務器的時候,服務器會把Cookie發給IE,而後由IE保存起來,當你在使用FireFox訪問服務器時,不可能把IE保存的Cookie發送給服務器。
Cookie是經過HTTP請求和響應頭在客戶端和服務器端傳遞的:
請求頭,客戶端發送給服務器端;
格式:Cookie:a=A;b=B;c=C。即多個Cookie用分號離開;
響應頭,服務器端發送給客戶端。
一個Cookie對象一個Set-Cookie:
Set-Cookie:a=A
Set-Cookie:b = B
Set-Cookie:c=C
若是服務器端發送重複的Cookie,那麼會覆蓋原有的Cookie。
cookies是瀏覽器爲Web服務器存儲的一小段信息。每次瀏覽器從某個服務器請求頁面時,它向服務器會送以前收到的cookies,它保存在瀏覽器下的某個文件夾下。
若是服務器端發送重複的Cookie那麼會覆蓋原有的Cookie,例如客戶端的第一個請求服務器端發送的Cookie是:Set-Cookie:a=A;第二請求服務器端發送的是:Set-Cookie:a=AA,那麼客戶端只留下一個Cookie,即:a=AA。
cookie不僅有name和value,Cookie還有生命,所謂生命就是Cookie在客戶端的有效時間,能夠經過setMaxAge(int) 來設置Cookie的有效時間。以秒爲單位。不設置默認爲關閉窗口,Cookie結束。
cookie 能夠有過時時間,這樣瀏覽器就知道何時能夠刪除cookie了。若是cookie沒有設置過時時間,當用戶關閉瀏覽器的時候,cookie就自動過時了。咱們能夠改變SESSION_EXPIRE_AT_BROWSER 的設置來控制session框架的這一行爲。缺省狀況下,SESSION_EXPIRE_AT_BROWSER 設置爲False,這樣,會話cookie能夠在用戶瀏覽器中保持有效達SESSION_COOKIE_AGE 秒(缺省設置是兩週,即1209600秒)。若是你不想用戶每次打開瀏覽器都必須從新登陸的話,用這個參數來幫助你。若是SESSION_EXPIRE_AT_BROWSER_CLOSE 設置爲 True ,當瀏覽器關閉時,Django會使cookie失效。
SESSION_COOKIE_AGE :設置cookie在瀏覽器中存活的時間
在settings.py中添加:
cookies是一種數據存儲技術,是將一段文本保存在客戶端(瀏覽器)的一種技術,而且能夠長時間的保存。
rep = HttpResponse(...) 或 rep = render(request, ...) 或 rep = redirect() rep.set_cookie(key,value,...) rep.set_signed_cookie(key,value,salt='加密鹽',...)
普通設置:
obj.set_cookie('tile' , 'name' , expires = value , path = '/')
加鹽設置(普通cookie是明文傳輸的,能夠直接在客戶端直接打開,因此須要加鹽,解鹽以後才能查看):
obj.set_signed_cookie('k' , 'v' , salt = 'name' )
咱們能夠查看源碼,發現HttpResponse() , render(),redirect() 都返回的是HttpResponse。
obj.set_cookie('tile', 'james', expires=value ,path='/', domain=None, secure=False, httponly=False)
參數:
class HttpResponseBase: def set_cookie(self, key, #鍵 value = '', #值 max_age = None, #超長時間cookie須要延續的時間(以秒爲單位)若是參數 #是\ None,這個cookie會延續到瀏覽器關閉爲止。 expires = None, #超長時間,expires默認None, cookie失效的實際日期 / 時間。 path = '/', #Cookie生效的路徑,瀏覽器只會把cookie回傳給帶有該路徑的頁面, # 這樣能夠避免將 cookie傳給站點中的其餘的應用。 # / 表示根路徑,特殊的:根路徑的cookie能夠被任何url的頁面訪問 domain = None, # Cookie生效的域名你可用這個參數來構造一個跨站cookie。 # 如, domain = ".example.com"所構造的cookie對下面這些站點都是可讀的: # www.example.com 、 www2.example.com和an.other.sub.domain.example.com 。 #若是該參數設置爲None ,cookie只能由設置它的站點讀取。secure = False, # 若是設置爲True ,瀏覽器將經過HTTPS來 回傳cookie。 httponly = False #只能http協議傳輸,沒法被JavaScript獲取 # (不是絕對,底層抓包能夠獲取到也能夠被覆蓋) ): pass
普通獲取:
request.COOKIES.get('k')
加鹽獲取:
cookies = request.get_signed_cookie('k' , salt = 'name' )
response.delete_cookie("cookie_key",path="/",domain=name)
代碼:
def logout(request): rep = redirect("/login/") # 刪除用戶瀏覽器上以前設置的user cookie的值 rep.delete_cookie("user") return rep
from django.shortcuts import render,redirect,HttpResponse import datetime from until import mysqlhelper # Create your views here. def cookie_auth(func): def weaper(request, *args, **kwargs): cookies = request.get_signed_cookie('k', salt='james') if cookies == 'v': return func(request) else: return HttpResponse("NG") return weaper now = datetime.datetime.utcnow() delta = datetime.timedelta(seconds=10) def login(request): if request.method == 'GET': return render(request, 'login.html') else: username = request.POST.get('N') password = request.POST.get('P') if username == 'james' and password == '123': obj = redirect('/modal') # obj.set_cookie("tile", "james", max_age = 1,, ) value = now + delta obj.set_cookie('tile', 'james', expires=value ,path='/', domain=None, secure=False, httponly=False) obj.set_signed_cookie('k', 'v', salt='james', ) return obj else: return render(request, 'login.html') def test(request): return render(request, 'layout.html') @cookie_auth def modal(request): sql = ''' SELECT teacher.id as tid,teacher.`name`as tname,class.title FROM day64.teacher LEFT JOIN teacher_class ON day64.teacher.id=day64.teacher_class.tid LEFT JOIN day64.class ON day64.teacher_class.cid=day64.class.id; ''' teacher_list = mysqlhelper.get_list(sql, []) res = {} for row in teacher_list: tid = row['tid'] if tid in res: res[tid]['titles'].append(row['title']) else: res[tid] = {'tid':row["tid"],'tname':row["tname"],'titles':[row["title"],]} class_list=mysqlhelper.get_list("SELECT id ,title FROM day64.class" ,[]) return render(request,'modal.html',{"list":res.values(),"class_list":class_list} )
咱們要作的就是顯示上次訪問時間。
views.py
from django.shortcuts import render, HttpResponse,redirect # Create your views here. from cookie_demo.models import UserInfo def login(request): if request.method == 'POST': user = request.POST.get('user') pwd = request.POST.get('pwd') user = UserInfo.objects.filter(user=user, pwd=pwd).first() if user: # 登陸成功 response = HttpResponse("OK") response.set_cookie('is_login', True) import datetime date = datetime.datetime(year=2019, month=5, day=28, hour=9, minute=17) response.set_cookie('username', user.user,expires=date) return response else: pass return render(request, 'cookie/login.html') def index(request): print('index: ', request.COOKIES) is_login = request.COOKIES.get('is_login') if is_login: username = request.COOKIES.get('username') import datetime now = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S') last_time = request.COOKIES.get('last_visit_time', "") response = render(request, 'cookie/index.html', {'username': username, 'last_time': last_time}) response.set_cookie('last_visit_time', now) return response else: return redirect('/cookie/login/')
index.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <h3>Hi, {{ username }}</h3> <p>上次登陸時間: {{ last_time }}</p> </body> </html>
login.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>index</title> </head> <body> <form action="" method="post"> {% csrf_token %} <p>用戶名:<input type="text" name="user"></p> <p>密碼:<input type="password" name="pwd"></p> <input type="submit" value="submit"> </form> </body> </html>
效果:
from django.shortcuts import render, HttpResponse, redirect import datetime # Create your views here. # 登陸驗證裝飾器 def login_auth(func): def inner(request, *args, **kwargs): # 獲取請求的全路徑 url = request.get_full_path() # /shopping/?nana=ppp # 服務器先拿到cookie,若是拿到則直接跳轉到shopping或者order視圖頁面 is_login = request.COOKIES.get('is_login') # xxx = request.get_signed_cookie('xxx' ,salt='123') # 拿到cookie 判斷是否是登陸狀態 if is_login: # 是登陸狀態直接調用被裝飾的函數,返回咱們想要的頁面 ret = func(request, *args, **kwargs) else: # 服務端若是拿不到正確的cookie就會重定向了login這個頁面,可是帶了一些參數 return redirect('/login/?next=%s'%url) # 當清楚瀏覽器緩存是直接登陸http://127.0.0.1:8000/shopping/,會跳轉到登陸頁面 # 而且在url後面拼上http://127.0.0.1:8000/login/?next=/shopping/ # 127.0.0.1:8000/login/?next=/shopping/?nana=ppp return ret return inner def login(request): if request.method == 'POST': # 裝飾器中redirect('/login/?next=%s'%url)經過get就能夠拿到next的值 # url = request.GET.get('name') username = request.POST.get('username') password = request.POST.get('password') if username == 'james' and password == '123': # 登陸成功後跳轉到該頁面 # obj = redirect(url) obj = HttpResponse("登陸成功") # 當咱們不指定path時,被裝飾的視圖函數頁面只登陸後均可以直接被訪問,而不須要從新登陸 obj.set_cookie('is_login', True) # 瀏覽器只會把cookie會傳給帶有該路徑的頁面 # 也就說當咱們登陸成功後,訪問shopping頁面時能夠直接登陸 # obj.set_cookie('is_login', True, path='/shopping/') # 可是咱們訪問order頁面時,仍然會跳到登陸頁面讓咱們從新登陸 now = datetime.datetime.now().strftime('%Y-%m-%d %X') # 設置cookie,在瀏覽器的請求頭中的cookie中咱們能夠看到咱們設置的額cookie # 並將登陸時間也寫到cookie中 obj.set_cookie('last_time', now) # 在瀏覽器中打開能夠看到一個key obj.set_cookie('username','james') obj.set_cookie('password','123') # 獲取cookie,並對cookie進行加鹽,加鹽後的123 是進行加密的遺傳字符嗎 obj.set_signed_cookie('james','durant',salt='123') # 登陸成功後對其進行重定向 return obj else: obj = HttpResponse("登陸失敗") return obj return render(request, 'login.html') # 退出登陸 def logout(request): obj = HttpResponse("註銷成功") # 登陸成功得到服務端發送來的cookie,刪除cookie, # 這樣我麼在瀏覽器中在輸入 http://127.0.0.1:8000/shopping/ # J就會在此跳到登陸頁面讓我門從新登陸 return obj # 購物頁面 def shopping(request): return render(request, 'shopping.html', locals()) # locals()用法:locals()能夠直接將函數中全部變量所有傳給模板 # 固然這可能會傳遞一些多餘的參數,有點浪費內存的嫌疑 # 登陸成功後再請求shopping頁面,在請求頭就能夠看到cookie中帶有鍵值對的形式: # Cookie: csrftoken = ybQexReWXIWaO0If0p0I7NubfBSvjUlSfR2EWWX8eKCwXbL8lDo4Kk3ar6Nbr5ZR; # last_time = "2018-09-13 18:13:17"; # name = james; # pwd = 123; # xxx = xxxxxx:1g0Ocf: 1kRB9Q0FVXlVzstrRbm4fJ61eF0 # 訂單頁面 @login_auth def order(request): return render(request, 'order.html', locals())
from django.contrib import admin from django.conf.urls import url # 須要先導入對應的app的views文件 from cookieapp import views urlpatterns = [ url(r'^admin/', admin.site.urls), url(r'^login/', views.login), url(r'^order/', views.order), url(r'^shopping/',views.shopping), url(r'^logout/', views.logout), ]
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <form action="" method="POST"> <p>用戶名:<input type="text" name="username"></p> <p>密碼: <input type="password" name="password"></p> <input type="submit"> </form> </body> </html>
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <h1>購物車頁面</h1> </body> </html>
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <H1>訂單頁面</H1> </body> </html>
session就是在服務器端的「Cookie」,將用戶數據保存在服務器端,遠比保存在用戶端要安全,方便和快捷的多。Session依賴於Cookie,可是與Cookie不一樣的地方就是在於session將全部的數據都放在服務器端,用戶瀏覽器的cookie中只會保存一個非明文的識別信息,好比哈希值。
Session是服務器端技術,利用這個技術,服務器在運行時能夠爲每個用戶的瀏覽器建立一個其獨享的session對象,因爲session爲用戶瀏覽器獨享,因此用戶在訪問服務器的web資源時,能夠把各自的數據放在各自的session中,當用戶再去訪問該服務器中的其餘web資源時,其餘web資源再從用戶各自的session中取出數據爲用戶服務。
Django的Session機器會向請求的瀏覽器發送cookie字符串。同時也會保存在本地一份,用來驗證瀏覽器登陸是否爲同一用戶。他存在於服務器,Django默認會把session存入數據庫中。
Session依賴於Cookie,若是瀏覽器不能保存cookie,那麼session就失效了。由於他須要瀏覽器的cookie和session作對比。session就是用來在服務器端保存用戶的會話狀態。
class backends.base.SessionBase # 這是全部會話對象的基類,包含標準的字典方法: __getitem__(key) Example: fav_color = request.session['fav_color'] __setitem__(key, value) Example: request.session['fav_color'] = 'blue' __delitem__(key) Example: del request.session['fav_color'] # 若是不存在會拋出異常 __contains__(key) Example: 'fav_color' in request.session get(key, default=None) Example: fav_color = request.session.get('fav_color', 'red') pop(key, default=__not_given) Example: fav_color = request.session.pop('fav_color', 'blue')
相似於字典數據類型的內置方法
keys() items() setdefault() clear() # 它還有下面的方法: flush() # 刪除當前的會話數據和會話cookie。常常用在用戶退出後,刪除會話。 set_test_cookie() # 設置一個測試cookie,用於探測用戶瀏覽器是否支持cookies。因爲cookie的 工做機制,你只有在下次用戶請求的時候才能夠測試。 test_cookie_worked() # 返回True或者False,取決於用戶的瀏覽器是否接受測試cookie。你必須在之 前先調用set_test_cookie()方法。 delete_test_cookie() # 刪除測試cookie。 set_expiry(value) # 設置cookie的有效期。能夠傳遞不一樣類型的參數值: • 若是值是一個整數,session將在對應的秒數後失效。例如request.session. set_expiry(300) 將在300秒後失效. • 若是值是一個datetime或者timedelta對象, 會話將在指定的日期失效 • 若是爲0,在用戶關閉瀏覽器後失效 • 若是爲None,則將使用全局會話失效策略 失效時間從上一次會話被修改的時刻開始計時。 get_expiry_age() # 返回多少秒後失效的秒數。對於沒有自定義失效時間的會話,這等同於SESSION_COOKIE_AGE. # 這個方法接受2個可選的關鍵字參數 • modification:會話的最後修改時間(datetime對象)。默認是當前時間。 •expiry: 會話失效信息,能夠是datetime對象,也能夠是int或None get_expiry_date() # 和上面的方法相似,只是返回的是日期 get_expire_at_browser_close() # 返回True或False,根據用戶會話是不是瀏覽器關閉後就結束。 clear_expired() # 刪除已經失效的會話數據。 cycle_key() # 建立一個新的會話祕鑰用於保持當前的會話數據。django.contrib.auth.login() 會調用這個方法
一、設置Sessions值 request.session['session_name'] ="admin" 二、獲取Sessions值 session_name = request.session["session_name"] 三、刪除Sessions值 del request.session["session_name"] 四、flush() 刪除當前的會話數據並刪除會話的Cookie。 這用於確保前面的會話數據不能夠再次被用戶的瀏覽器訪問 五、get(key, default=None) fav_color = request.session.get('fav_color', 'red') 六、pop(key) fav_color = request.session.pop('fav_color') 七、keys() 八、items() 九、setdefault() 10 用戶session的隨機字符串
用戶session的隨機字符串舉例:
request.session.session_key # 將全部Session失效日期小於當前日期的數據刪除 request.session.clear_expired() # 檢查 用戶session的隨機字符串 在數據庫中是否 request.session.exists("session_key") # 刪除當前用戶的全部Session數據 request.session.delete("session_key") request.session.set_expiry(value) *若是value是個整數,session會在些秒數後失效。 *若是value是個datatime或timedelta,session就會在這個時間後失效。 *若是value是0, 用戶關閉瀏覽器session就會失效。 *若是value是None, session會依賴全局session失效策略。
Django默認支持Session,而且默認是將Session數據存儲在數據庫中,即:django_session 表中。 a. 配置 settings.py SESSION_ENGINE = 'django.contrib.sessions.backends.db' # 引擎(默認) 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,默認修改以後才保存(默認)
session下次經過cookie中的sessionID(鍵)獲取用戶信息值(值)
1,會話保持,記住用戶的登陸狀態(WEB網站,分佈式架構)
2,避免了敏感信息保存在客戶端,防止客戶端修改cookie信息(和cookie的區別)
session的過時時間:django默認設置是2周 ,若是session過時,瀏覽器再攜帶以前的cookie就不能免登錄了。由於cookie已經失效了。
前端:若是超出了session的過時時間,那麼瀏覽器會自動將對應的cookie刪除掉
後端:django沒有對過時的session作任何處理
python manage.py clearsessions
固然,若是用戶在過時時間內主動退出登陸,那麼django會將該用戶對應的session數據給刪除掉 (request.session.flush())
可是若是用戶在登陸完之後沒有主動退出,而且超出了過時時間,用戶須要從新登陸,但django中的過時session是不清除的,須要按期清理過時的session數據。
當客戶端第一次請求session時,服務器端會爲客戶端創造一個session對象,而且生成一個session ID (經過加密算法)。而後保存在cookie中,當用戶再次登陸時,客戶端經過cookie,將session ID傳到服務器,去和服務器中的session ID進行比對,尋找這個session,而後根據查找結果執行對應的操做。
由於session ID 是保存在cookie中,而cookie是存在於客戶端,因此session ID 並不安全。
爲了不session ID 被盜,咱們能夠這樣作:
Session是大多數網站都須要具有的功能,Django爲咱們提供了一個通用的session框架,而且可使用多種session數據的保存方式:
一般狀況下,沒有特別需求的話,請使用保存在數據庫內的方式,儘可能不要保存在cookie內。
django的session框架支持匿名會話,封裝了cookies的發送和接收過程。cookie包含一個會話ID而不是數據自己(除非你使用的是基於後端的cookie)。
django的會話框架徹底的,惟一的基於cookie。它不像PHP同樣,把會話的ID放在URL中,那樣不只使得URL變得醜陋,並且使得你的網站易於受到經過「Referer」頭部進行竊取會話ID的攻擊。
session的應用要依賴於cookie(session就是cookie的變種)
1,每次用戶第一次訪問服務端,把用戶的惟一字符串session_id加到cookie裏面發送給客戶端;
當用戶登陸以後,生成一個字典{key : value},將字典存入session,key是自動生成的一段字符串表示,返回cookie,value是一個自定義格式的字典。
2,服務器端保存隨機字符串(sessionID :{用戶信息}) 服務端
當咱們在django中用到session時,cookie由服務端隨機生成,寫到瀏覽器的cookie中。每一個瀏覽器都有本身的cookie值,是session尋找用戶信息的惟一標識。每一個瀏覽器請求到後臺接受的request.session 等價於在1中的session字典key (cookie)對應的value。
3,session的好處就是客戶端只有cookie的值,可是始終沒有用戶信息。
用法:request.session.get('k1') request.session['k1'] = 'v1'
session依賴於cookie,cookie保存在瀏覽器。session保存在服務器 端。
注意:這裏須要注意在session中,咱們能夠設置多個key:value的值,方便咱們作不少事情,好比判斷哪一個用戶:
若是用戶登陸後,那麼他確定有一個cookie,而當他訪問購物車的時候,怎麼判斷是哪一個用戶呢?咱們能夠在session設置,當用戶登陸的時候,咱們把用戶名增長到session中,那麼用戶攜帶cookie訪問的時候,咱們就能判斷是哪一個用戶來訪問的。
好比下面的對應關係:
user1
cookie : 001
server session(舉例格式)
{session:001 {'IS_LOGIN':'True',username:'james'}}
from django.shortcuts import render,redirect,HttpResponse # Create your views here. def login(request): if request.method == 'POST': username = request.POST.get('username') password = request.POST.get('password') if username == 'james' and password == '123': # 設置session request.session['IS_Login'] = True return redirect('/app01/home') return render(request, 'login.html') def home(request): # 獲取session is_login = request.session.get("IS_LOGIN", False) if is_login: return HttpResponse('order') else: return redirect('/app01/login/')
def session_test(request): # 設置session值,會將其存到db.sqlite數據庫中的django_session表中 # 每發送一次請求就會在django_session表中添加一條記錄 request.session['username'] = 'james' request.session['is_login'] = True ''' 1,生成一個隨機字符串 2,把隨機字符串以cookie的形式寫回給瀏覽器 3,會在數據庫中存{'隨機字符串': {'username' : 'james' , 'is_login': True} ''' return HttpResponse("ok") def get_session(request): # 在瀏覽器中輸入路由地址就會訪問訪問該視圖函數 # 獲取session值,可是必定要先獲取session值,不然獲取session時會報錯 # name=request.session['username'] # is_login=request.session['is_login'] # print(name) # print(is_login) # session取值的兩種方式,字典key或者get進行取值 # request.session['k1'] # request.session.get('k1', None) # 設置session的值 # request.session['k1'] = 123 # name=request.session.setdefault('username', 123) # 若是session中的username有值就不會設置,無值則進行設置 # print(name) #-----123 # del request.session['k1'] # 經過key將session的值進行刪除 # print(request.session.session_key) # 取出表django_session表中session_key字段對應的值 # 將全部Session失效日期小於當前日期的數據刪除 # request.session.clear_expired() # 判斷session表中session_key字段的值是否存在,返回值爲布爾值 # print(request.session.exists("b16mh23xajc2u69vazvivf8ruo4ilumi")) # 會刪除數據庫的session表中的session的記錄,可是瀏覽器中的session id還在 # request.session.delete() # 刪除當前的會話數據並刪除會話的Cookie。 # 一般用它,他會把數據庫以及瀏覽器會話中的session id都刪除 # (調用視圖函數test能夠看到效果的確是已經被刪除) request.session.flush() return HttpResponse("OK")
flush()方法是比較安全的一種作法,並且一次性將session中的全部內容所有清空,確保不留後患,可是也有很差的地方,那就是若是你在session中夾帶了一點「私貨」,會被一併刪除,這一點必定要注意。
好比登出視圖函數:
def logout(request): if not request.session.get('is_login', None): # 若是原本就未登陸,也就沒有登出一說 return redirect("/index/") request.session.flush() # 或者使用下面的方法 # del request.session['is_login'] # del request.session['user_id'] # del request.session['user_name'] return redirect("/index/")
from django.utils.decorators import method_decorator # 在視圖函數中裝飾類 須要先導入method_decorator模塊 from django.views import View # 在類上加裝飾器須要指定name的值,也就是要指定裝飾類內的那個函數 # 當咱們登陸成功後就會直接跳轉到咱們要登陸的頁面 # @method_decorator(login_auth, name='post') # @method_decorator(login_auth, name='get') class MyOrder(View): # 將裝飾器傳入進去 # @method_decorator(login_auth) # 咱們能夠重寫dispatch函數來實現 def dispatch(self, request, *args, **kwargs): # 咱們能夠重寫dispatch函數來實現相似於裝飾器的效果 # dispatch 內部根據反射來實現函數執行 # 集成父類view的屬性 ret = super().dispatch(request, *args, **kwargs) return ret # 在cbv上加裝飾器,須要用method_decorator修飾一下 @method_decorator(login_auth) def get(self, request): return HttpResponse('get') def post(self,request): return HttpResponse('post') ''' 1 導入from django.utils.decorators import method_decorator 2 加載get,post,dispatch方法上:@method_decorator(login_auth) 3 加在類上:@method_decorator(login_auth,name='get') '''
cookie看似解決了HTTP(短鏈接,無狀態)的會話保持問題,但把所有用戶數據保存在客戶端,存在安全隱患。
因而cookie+session出現了,咱們,咱們能夠把關於用戶的數據保存在服務端,在客戶端cookie里加一個sessionID(隨機字符串)。
基於以上緣由:cookie+session組成就成立了,而且結束了單單使用cookie作會話保持的方式。
使用Session和Cookie的好處:Cookie能夠理解爲一個身份證ID,你只要拿着他去和Server端進行通訊,若是你沒有這個ID,那麼server端也不知道你是誰。
舉個例子:我在寫博客的時候,在作Cookie和Session的實驗,把Cookie刪掉了,當我保存的時候直接給我提出來了,爲何呢?就是由於server端不知道我是誰了,由於我已經沒有祕鑰了。
因此,只要Session和Cookie任意一方失效,就能夠理解爲:Cookie失效至關於身份證ID過時,須要從新認證才能夠繼續使用。Session失效就至關於銀行裏的數據標識此ID無效,也須要從新申請。
1,當用戶來訪問服務端的時候,服務端生成一個隨機字符串;
2,當用戶登陸成功後,把{sessionID : 隨機字符串} 組織成鍵值對 加到cookie裏發送給用戶;
3,服務器以發送給客戶端cookie中的隨機字符串作鍵,用戶信息作值,保存用戶信息;
用戶登陸的兩種方式:
1,使用login() 和logout()這兩個內置函數實現登陸和退出;缺點就是用戶的登陸時在操做同一個request.user。致使同一臺電腦上不能同時登陸兩個用戶;
2,若是同一臺電腦的同一個網站,登陸多個帳號,爲了防止串號,不能再使用login() 和logout()函數了,能夠經過session和cookie來實現這個需求;
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <form action="login.html" method="post"> <input type="text" name="username"> <input type="password" name="pwd"> <input type="submit" value="submit"> </form> </body> </html>
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <style> .header{ height: 48px; } </style> </head> <body> <div class="header"> <div style="float: right;">{{ username }}</div> <div style="float:right;"><a href="logout.html">註銷</a></div> </div> <div style="height: 500px; background-color: #ddd"></div> </body> </html>
from django.shortcuts import render,redirect,HttpResponse # Create your views here. def login(request): if request.method == 'POST': username = request.POST.get('username') password = request.POST.get('password') if username == 'james' and password == '123': # 設置session request.session['IS_Login'] = True request.session['USERNAME'] = 'james' return redirect('/Manytable/home/') elif username == 'durant' and password == '123': request.session['IS_LOGIN'] = True request.session['USERNAME'] = 'durant' return redirect('/Manytable/home/') return render(request, 'Manytable/login.html') def home(request): # 獲取session is_login = request.session.get("IS_LOGIN", False) if is_login: username = request.session.get("USERNAME", False) return render(request, 'Manytable/home.html', {'username':username}) # return HttpResponse('order') else: return redirect('/Manytable/login/')
from django.contrib import admin from django.urls import path from django.conf.urls import url # 須要先導入對應的app的views文件 from Manytable import views # admin 後臺的路由,先註釋掉 urlpatterns = [ url(r'^admin/', admin.site.urls), # 你的路由,重點是引號中的正則表達式和後面的業務邏輯函數 url(r'^login/',views.login), url(r'^index/',views.home), ]
須要的頁面: #login.html:登陸頁面,提供登陸表單; #index1.html:主頁,顯示當前用戶名稱,若是沒有登陸,顯示您還沒登陸; #index2.html:主頁,顯示當前用戶名稱,若是沒有登陸,顯示您還沒登陸;
思考:若是第二我的在同一個瀏覽器上登陸,Django-session表會怎麼樣呢?
驗證碼能夠去識別發出請求的是人仍是程序!固然,若是聰明的程序能夠去分析驗證碼圖片!可是分析圖片也不是一件容易的事情,由於通常驗證碼圖片都會帶有干擾線,人都看不清,那麼程序必定分析不出來。
參考文獻:https://www.cnblogs.com/chenchao1990/p/5283725.html
https://blog.csdn.net/qq_32446743/article/details/79482536
https://www.jianshu.com/p/59cb3ecd81a4
https://www.cnblogs.com/sui776265233/p/9643055.html