Django學習筆記(5)——cookie和session

一,前言

1.1,什麼是會話跟蹤技術

  在JavaWeb中,客戶向某一服務器發出第一個請求開始,會話就開始了,直到客戶關閉了瀏覽器會話結束。在一個會話的多個請求中共享數據,這就是會話跟蹤技術。html

  例如在一個會話中的請求以下(請求銀行主頁):前端

  • 請求登陸(請求參數是用戶名和密碼)
  • 請求轉帳(請求參數與轉帳相關的數據)
  • 請求信譽卡還款(請求參數與還款相關的數據)

  在上面會話中,當前用戶信息必須在這個會話中共享的,由於登陸的是張三,那麼在轉帳和還款時必定是相對張三的轉帳和還款!這就說明咱們必須在一個會話過程當中有共享數據的能力。python

  在程序中,會話跟蹤是很重要的事情。理論上,一個用戶的全部請求都應該屬於同一個會話,而另外一個用戶的全部請求則該屬於另外一個會話,兩者不能混淆。例如,用戶A在超市購買的任何商品都應該放在A的購物車內,不管是用戶A何時購買的,這都是屬於同一個會話,不能放在用戶B或者用戶C的購物車內,這不屬於同一個會話。mysql

1.2,會話路徑技術使用Cookie 或 session 完成

  咱們知道HTTP協議是無狀態協議,也就是說每一個請求都會獨立的! 沒法記錄前一次請求的狀態。可是HTTP協議中可使用Cookie來完成會話跟蹤技術!web

  在JavaWeb開發中,使用session來完成會話跟蹤,session底層依賴Cookie技術。正則表達式

  • cookie就是一段字符串,保存於本機電腦上
  • session保存於服務器,用來保存用戶的會話信息,依賴於Cookie

  cookie是經過在客戶端記錄信息肯定用戶身份,Session是經過在服務端記錄信息肯定用戶身份。算法

 1.3,cookie與session的實現原理

  上圖很明顯的展現了Django的session和cookie的實現原理。服務器會生成兩份相同的cookie字符串,一份保存在本地,一份發向請求的瀏覽器。瀏覽器將會受到的cookie字符串保存下來,當下次再發請求時,會將信息與這段cookie一同發送到服務器,服務器獲得這段cookie會與本地保存的那份判斷是否相同,若是相同就表示用戶已經登陸成功,保存用戶登陸成功的狀態。Django的session保存在數據庫中的數據至關於一個大字典,key爲cookie的字符串,value還是一個字典,字典的key和value爲用戶設置的相關信息,這樣就能夠方便的存取session裏面的信息。sql

 1.4,HTTP無狀態性

  HTTP被設計爲「無狀態」,每次請求都處於相同的空間中。在一次請求和下一次狀況之間沒有任何狀態保持,咱們沒法根據請求的任何方面(IP地址,用戶代理等)來識別同一人的連續請求,因此HTTP協議不具有保存以前發送過的請求或響應的功能。數據庫

  協議對於事務處理沒有記憶能力,對同一個URL請求沒有上下文關係,每次的請求都是獨立的,它的執行狀況和結果與以前的請求和以後的請求時無直接關係的。它不會受前面的請求應答狀況直接影響,也不會直接影響後面的請求應答狀況。服務器中沒有保存客戶端的狀態,客戶端必須每次帶上本身的狀態去請求服務器。django

  若是說每一一種機制用來處理無狀態,那麼就須要花費時間不停的進行身份驗證,正是這樣,HTTP引入了session和cookie,即保持了HTTP的無狀態性,也使得HTTP的應用稱爲有狀態的。

二,Cookie概述

2.1,什麼叫 Cookie

  Cookie翻譯成中文是小甜點,小餅乾的意思。在HTTP中它表示服務器送給客戶端瀏覽器的小甜點。其實Cookie是 key-value 結構,相似於一個python中的字典。隨着服務器端的響應發送給客戶端瀏覽器。而後客戶端瀏覽器會把Cookie保存起來,當下一次再訪問服務器時把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能夠看到其信息:

  在響應頭,咱們也能夠看到其信息:

 

 

 2.2,HTTP的Cookie規範

  • Cookie大小上限爲4KB;
  • 一個服務器最多在客戶端瀏覽器上保存20個Cookie;
  • 一個瀏覽器最多保存300個Cookie

  上面的數據只是HTTP的Cookie規範,可是在瀏覽器大戰的今天,一些瀏覽器爲了戰勝對手,爲了展現本身的能力起見,可能對Cookie規範「擴展」了一些,例如每一個Cookie的大小爲8KB,最多可保存500個Cookie等!但也不會出現將你的硬盤佔滿的可能!

  注意:不一樣瀏覽器之間是不共享Cookie的,也就是說在你使用IE訪問服務器的時候,服務器會把Cookie發給IE,而後由IE保存起來,當你在使用FireFox訪問服務器時,不可能把IE保存的Cookie發送給服務器。

2.3,Cookie的用途

  • 服務器使用Cookie來跟蹤客戶端狀態
  • 保存購物車
  • 顯示上次登陸名

2.4,Cookie與HTTP頭

  Cookie是經過HTTP請求和響應頭在客戶端和服務器端傳遞的:

  • Cookie:

    請求頭,客戶端發送給服務器端;

    格式:Cookie:a=A;b=B;c=C。即多個Cookie用分號離開;

  • Set-Cookie:

    響應頭,服務器端發送給客戶端。

    一個Cookie對象一個Set-Cookie:

    Set-Cookie:a=A

    Set-Cookie:b = B

    Set-Cookie:c=C

2.5,Cookie的覆蓋

  若是服務器端發送重複的Cookie,那麼會覆蓋原有的Cookie。

  cookies是瀏覽器爲Web服務器存儲的一小段信息。每次瀏覽器從某個服務器請求頁面時,它向服務器會送以前收到的cookies,它保存在瀏覽器下的某個文件夾下。

 

  若是服務器端發送重複的Cookie那麼會覆蓋原有的Cookie,例如客戶端的第一個請求服務器端發送的Cookie是:Set-Cookie:a=A;第二請求服務器端發送的是:Set-Cookie:a=AA,那麼客戶端只留下一個Cookie,即:a=AA。

2.6,Cookie 的生命週期

  cookie不僅有name和value,Cookie還有生命,所謂生命就是Cookie在客戶端的有效時間,能夠經過setMaxAge(int) 來設置Cookie的有效時間。以秒爲單位。不設置默認爲關閉窗口,Cookie結束。

  • cookie. setMaxAge(-1):cookie的maxAge屬性的默認值就是-1,表示只在瀏覽器內存中存活。一旦關閉瀏覽器窗口,那麼cookie就會消失。
  • cookie.setMaxAge(60*60):表示cookie對象可存活1小時。當生命大於0時,瀏覽器會把Cookie保存到硬盤上,就算關閉瀏覽器,就算重啓客戶端電腦,cookie也會存活1小時;
  • cookie.setMaxAge(0):cookie生命等於0是一個特殊的值,它表示cookie被做廢!也就是說,若是原來瀏覽器已經保存了這個Cookie,那麼能夠經過Cookie的setMaxAge(0)來刪除這個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中添加:

 

2.7,Django中的cookie語法

  cookies是一種數據存儲技術,是將一段文本保存在客戶端(瀏覽器)的一種技術,而且能夠長時間的保存。

1,設置cookie

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。

2,cookie參數介紹:

            obj.set_cookie('tile', 'james', expires=value ,path='/',
                           domain=None, secure=False, httponly=False)

  參數:

  • 1,max_age = 1 : cookie生效的時間,單位是秒
  • 2,expires:具體過時日期
  • 3,path = '/' :  指定哪一個url 能夠訪問到cookie,‘/’ 表示全部,即 path = '/'
  • 4,domain = None(None表明當前域名):指定哪一個域名以及它下面的二級域名(子域名)能夠訪問這個cookie
  • 5,secure = False :https安全相關
  • 6,httponly = False:限制只能經過HTTP傳輸,JS沒法在傳輸中獲取和修改。
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

  

3,獲取cookie

  普通獲取:

request.COOKIES.get('k')

  加鹽獲取:

cookies = request.get_signed_cookie('k' , salt = 'name' )

  

4,刪除cookie

response.delete_cookie("cookie_key",path="/",domain=name)

  代碼:

def  logout(request):
    rep = redirect("/login/")
    #  刪除用戶瀏覽器上以前設置的user  cookie的值
    rep.delete_cookie("user")
    return  rep

  

5,嘗試給每一個視圖函數裝飾cookie認證功能

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} )

  

2.8,實例:保存上次訪問時間

  咱們要作的就是顯示上次訪問時間。

  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>

  效果:

 

2.9,實例:Cookie版登錄校驗

views視圖代碼:

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())

  

url路由配置

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),
]

  

template模板代碼

login.html

<!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>

  

shopping.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

    <h1>購物車頁面</h1>

</body>
</html>

  

order.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

    <H1>訂單頁面</H1>

</body>
</html>

  

結果展現:(登錄頁面:127.0.0.1:8000/login.login)

登錄成功:

cookie展現

 

 

三,session概述

  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就是用來在服務器端保存用戶的會話狀態。

3.1,Django中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() 
會調用這個方法

  

  • 獲取session:request.session[key]
  • 設置session:request.session[key] = value
  • 刪除session:del  request[key]
一、設置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失效策略。

  

3.2,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,默認修改以後才保存(默認)

  

3.3,session的做用

  session下次經過cookie中的sessionID(鍵)獲取用戶信息值(值)

1,會話保持,記住用戶的登陸狀態(WEB網站,分佈式架構)

2,避免了敏感信息保存在客戶端,防止客戶端修改cookie信息(和cookie的區別)

session的過時時間

  session的過時時間:django默認設置是2周 ,若是session過時,瀏覽器再攜帶以前的cookie就不能免登錄了。由於cookie已經失效了。

  前端:若是超出了session的過時時間,那麼瀏覽器會自動將對應的cookie刪除掉

  後端:django沒有對過時的session作任何處理

如何刪除後臺保留的一些過時的session信息

python manage.py clearsessions

  固然,若是用戶在過時時間內主動退出登陸,那麼django會將該用戶對應的session數據給刪除掉  (request.session.flush())

  可是若是用戶在登陸完之後沒有主動退出,而且超出了過時時間,用戶須要從新登陸,但django中的過時session是不清除的,須要按期清理過時的session數據。

3.4,session ID的做用

  當客戶端第一次請求session時,服務器端會爲客戶端創造一個session對象,而且生成一個session ID (經過加密算法)。而後保存在cookie中,當用戶再次登陸時,客戶端經過cookie,將session ID傳到服務器,去和服務器中的session ID進行比對,尋找這個session,而後根據查找結果執行對應的操做。

  由於session ID 是保存在cookie中,而cookie是存在於客戶端,因此session ID 並不安全。

  爲了不session ID 被盜,咱們能夠這樣作:

  • 1,敏感操做須要用戶輸入密碼來進行二次認證
  • 2,網站HTTPS化,提升消息傳遞過程當中的安全係數
  • 3,用戶使用一個密鑰對參數進行hash,這樣即便cookie被盜取,也會由於沒有密鑰而沒法獲取sessionID。

3.5,session的保存方式

  Session是大多數網站都須要具有的功能,Django爲咱們提供了一個通用的session框架,而且可使用多種session數據的保存方式:

  • 保存在數據庫內
  • 保存到緩存
  • 保存到文件內
  • 保存到cookie內

  一般狀況下,沒有特別需求的話,請使用保存在數據庫內的方式,儘可能不要保存在cookie內。

  django的session框架支持匿名會話,封裝了cookies的發送和接收過程。cookie包含一個會話ID而不是數據自己(除非你使用的是基於後端的cookie)。

  django的會話框架徹底的,惟一的基於cookie。它不像PHP同樣,把會話的ID放在URL中,那樣不只使得URL變得醜陋,並且使得你的網站易於受到經過「Referer」頭部進行竊取會話ID的攻擊。

3.6,session流程解析

  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保存在服務器 端。

3.7,示例

  注意:這裏須要注意在session中,咱們能夠設置多個key:value的值,方便咱們作不少事情,好比判斷哪一個用戶:

  若是用戶登陸後,那麼他確定有一個cookie,而當他訪問購物車的時候,怎麼判斷是哪一個用戶呢?咱們能夠在session設置,當用戶登陸的時候,咱們把用戶名增長到session中,那麼用戶攜帶cookie訪問的時候,咱們就能判斷是哪一個用戶來訪問的。

好比下面的對應關係:

user1

cookie : 001

  

server session(舉例格式)

{session:001 {'IS_LOGIN':'True',username:'james'}}

  

3.7.1,一段簡單的Django中實現session的代碼,判斷用戶是否已經成功登錄

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/')

  

3.7.2 在視圖中使用session

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/")

  

3.7.3 在視圖函數中使用裝飾器裝飾CBV

 

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 + session

1,cookie引入session

  cookie看似解決了HTTP(短鏈接,無狀態)的會話保持問題,但把所有用戶數據保存在客戶端,存在安全隱患。

  因而cookie+session出現了,咱們,咱們能夠把關於用戶的數據保存在服務端,在客戶端cookie里加一個sessionID(隨機字符串)。

  基於以上緣由:cookie+session組成就成立了,而且結束了單單使用cookie作會話保持的方式。

2,Session和Cookie的好處

  使用Session和Cookie的好處:Cookie能夠理解爲一個身份證ID,你只要拿着他去和Server端進行通訊,若是你沒有這個ID,那麼server端也不知道你是誰。

  舉個例子:我在寫博客的時候,在作Cookie和Session的實驗,把Cookie刪掉了,當我保存的時候直接給我提出來了,爲何呢?就是由於server端不知道我是誰了,由於我已經沒有祕鑰了。

  因此,只要Session和Cookie任意一方失效,就能夠理解爲:Cookie失效至關於身份證ID過時,須要從新認證才能夠繼續使用。Session失效就至關於銀行裏的數據標識此ID無效,也須要從新申請。

3,cookie+session 的工做流程

1,當用戶來訪問服務端的時候,服務端生成一個隨機字符串;

2,當用戶登陸成功後,把{sessionID : 隨機字符串} 組織成鍵值對 加到cookie裏發送給用戶;

3,服務器以發送給客戶端cookie中的隨機字符串作鍵,用戶信息作值,保存用戶信息;

 

 

代碼梳理

用戶登陸的兩種方式:

1,使用login() 和logout()這兩個內置函數實現登陸和退出;缺點就是用戶的登陸時在操做同一個request.user。致使同一臺電腦上不能同時登陸兩個用戶;

2,若是同一臺電腦的同一個網站,登陸多個帳號,爲了防止串號,不能再使用login() 和logout()函數了,能夠經過session和cookie來實現這個需求;

1,login.html

<!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>

  

2,home.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>

  

3,view.py

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/')

  

4,mysite/urls.py

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),
]

  

5,格式以下:

 

 

 做業練習

1,登陸案例

須要的頁面:
#login.html:登陸頁面,提供登陸表單;

#index1.html:主頁,顯示當前用戶名稱,若是沒有登陸,顯示您還沒登陸;

#index2.html:主頁,顯示當前用戶名稱,若是沒有登陸,顯示您還沒登陸;

  思考:若是第二我的在同一個瀏覽器上登陸,Django-session表會怎麼樣呢?

2,驗證碼案例

  驗證碼能夠去識別發出請求的是人仍是程序!固然,若是聰明的程序能夠去分析驗證碼圖片!可是分析圖片也不是一件容易的事情,由於通常驗證碼圖片都會帶有干擾線,人都看不清,那麼程序必定分析不出來。

 

 

參考文獻: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

相關文章
相關標籤/搜索