69-django-forms組件源碼刨析、cookie與session

今日內容概要

  • forms組件源碼html

  • cookie與sessionpython

今日內容詳細

forms組件源碼

 1 """
 2 切入點:
 3     form_obj.is_valid()
 4 """
 5 def is_valid(self):
 6         """
 7         Returns True if the form has no errors. Otherwise, False. If errors are
 8         being ignored, returns False.
 9         """
10    return self.is_bound and not self.errors
11    # 若是is_valid要返回True的話 那麼self.is_bound要爲True self.errors要爲Flase
12   
13   
14 self.is_bound = data is not None or files is not None  # 只要你傳值了確定爲True
15 
16 
17 @property
18 def errors(self):
19         "Returns an ErrorDict for the data provided for the form"
20         if self._errors is None:
21             self.full_clean()
22         return self._errors
23 
24 # forms組件全部的功能基本都出自於該方法
25 def full_clean(self):
26       self._clean_fields()  # 校驗字段 + 局部鉤子
27     self._clean_form()  # 全局鉤子
28     self._post_clean() 
29 
30 
31 # 經過看源碼獲得得第二種添加鉤子提示的方式
32  from django.core.exceptions import NON_FIELD_ERRORS, ValidationError
33 
34     def clean_username(self):
35         username = self.cleaned_data.get('username')
36         if '666' in username:
37             # self.add_error('username', '6個粑粑憨逼')
38             raise ValidationError('6個粑粑憨逼')
39         return username
40         

cookie與session

"""
發展史
    1.網站都沒有保存用戶功能的需求 全部用戶訪問返回的結果都是同樣的
        eg:新聞、博客、文章...
    
    2.出現了一些須要保存用戶信息的網站
        eg:淘寶、支付寶、京東...
        
        以登錄功能爲例:若是不保存用戶登錄狀態 也就意味着用戶每次訪問網站都須要重複的輸入用戶名和密碼(你以爲這樣的網站你還想用嗎?)
        當用戶第一次登錄成功以後 將用戶的用戶名密碼返回給用戶瀏覽器 讓用戶瀏覽器保存在本地,以後訪問網站的時候瀏覽器自動將保存在瀏覽器上的用戶名和密碼發送給服務端,服務端獲取以後自動驗證
        早起這種方式具備很是大的安全隱患
        
        
        優化:
            當用戶登錄成功以後,服務端產生一個隨機字符串(在服務端保存數據,用kv鍵值對的形式),交由客戶端瀏覽器保存
            隨機字符串1:用戶1相關信息
            隨機字符串2:用戶2相關信息
            隨機字符串3:用戶3相關信息
            以後訪問服務端的時候,都帶着該隨機字符串,服務端去數據庫中比對是否有對應的隨機字符串從而獲取到對應的用戶信息
            
    
  
可是若是你拿到了截獲到了該隨機字符串,那麼你就能夠冒充當前用戶 其實仍是有安全隱患的


你要知道在web領域沒有絕對的安全也沒有絕對的不安全
"""
cookie
    服務端保存在客戶端瀏覽器上的信息均可以稱之爲cookie
  它的表現形式通常都是k:v鍵值對(能夠有多個)
session
    數據是保存在服務端的而且它的表現形式通常也是k:v鍵值對(能夠有多個)
    
    
下述內容暫時瞭解便可 先給我搞明白最簡單的cookie與session使用再說話!
還想了解見:https://www.cnblogs.com/Dominic-Ji/p/10886902.html
token
    session雖然數據是保存在服務端的 可是禁不住數據量大
  服務端再也不保存數據
      登錄成功以後 將一段用戶信息進行加密處理(加密算法以後你公司開發知道)
    將加密以後的結果拼接在信息後面 總體返回給瀏覽器保存 
    瀏覽器下次訪問的時候帶着該信息 服務端自動切去前面一段信息再次使用本身的加密算法
    跟瀏覽器尾部的密文進行比對
jwt認證
    三段信息
  (後期會講 結合django一塊兒使用) 
    
總結:
    1.cookie就是保存在客戶端瀏覽器上的信息
    2.session就是保存在服務端上的信息
    3.session是基於cookie工做的(其實大部分的保存用戶狀態的操做都須要使用到cookie)

cooike

1 '''
2 cookie 是一個很是具體的東西,指的就是瀏覽器裏面能永久存儲的一種數據,僅僅是
3 瀏覽器實現的一種數據存儲功能。
4 
5 cookie由服務器生成,發送給瀏覽器,瀏覽器把cookie以kv形式保存到某個目錄下的
6 文本文件內,下一次請求同一網站時會把該cookie發送給服務器。因爲cookie是存在
7 客戶端上的,因此瀏覽器加入了一些限制確保cookie不會被惡意使用,同時不會佔據
8 太多磁盤空間,因此每一個域的cookie數量是有限的。
9 '''

session

 1 '''
 2 session 從字面上講,就是會話。這個就相似於你和一我的交談,你怎麼知道當前和
 3 你交談的是張三而不是李四呢?對方確定有某種特徵(長相等)代表他就是張三。
 4 
 5 session 也是相似的道理,服務器要知道當前發請求給本身的是誰。爲了作這種區分,
 6 服務器就要給每一個客戶端分配不一樣的「身份標識」,而後客戶端每次向服務器發請求的
 7 時候,都帶上這個「身份標識」,服務器就知道這個請求來自於誰了。至於客戶端怎麼
 8 保存這個「身份標識」,能夠有不少種方式,對於瀏覽器客戶端,你們都默認採用 cookie
 9  的方式。
10 
11 服務器使用session把用戶的信息臨時保存在了服務器上,用戶離開網站後session會
12 被銷燬。這種用戶信息存儲方式相對cookie來講更安全,但是session有一個缺陷:如
13 果web服務器作了負載均衡,那麼下一個操做請求到了另外一臺服務器的時候session會
14 丟失。 

Cookie操做

 1 # 雖然cookie是服務端告訴客戶端瀏覽器須要保存內容
 2 # 可是客戶端瀏覽器能夠選擇拒絕保存 若是禁止了 那麼 只要是須要記錄用戶狀態的網站登錄功能都沒法使用了
 3 
 4 # 視圖函數的返回值
 5 return HttpResponse()
 6 return render()
 7 return redirect()
 8 
 9 
10 obj1 = HttpResponse()
11 # 操做cookie
12 return obj1
13 
14 obj2 = render()
15 # 操做cookie
16 return obj2
17 
18 obj3 = redirect()
19 # 操做cookie
20 return obj3
21 # 若是你想要操做cookie,你就不得不利用obj對象
22 
23 
24 """
25 設置cookie
26     obj.set_cookie(key,value)
27 獲取cookie
28     request.COOKIES.get(key)
29 在設置cookie的時候能夠添加一個超時時間
30     obj.set_cookie('username', 'jason666',max_age=3,expires=3)
31     
32     max_age
33     expires
34         二者都是設置超時時間的 而且都是以秒爲單位
35         須要注意的是 針對IE瀏覽器須要使用expires
36 主動刪除cookie(註銷功能)
37   request.delete_cookie('username')  
38     
39 """
40 # 咱們完成一個真正的登錄功能
41 # 校驗用戶是否登錄的裝飾器
42 """
43 用戶若是在沒有登錄的狀況下想訪問一個須要登錄的頁面
44 那麼先跳轉到登錄頁面 當用戶輸入正確的用戶名和密碼以後
45 應該跳轉到用戶以前想要訪問的頁面去 而不是直接寫死
46 """
47 def login_auth(func):
48     def inner(request,*args,**kwargs):
49         # print(request.path_info)
50         # print(request.get_full_path())  # 可以獲取到用戶上一次想要訪問的url
51         target_url = request.get_full_path()
52         if request.COOKIES.get('username'):
53             return func(request,*args,**kwargs)
54         else:
55             return redirect('/login/?next=%s'%target_url)
56     return inner
57 
58 def login(request):
59     if request.method == 'POST':
60         username = request.POST.get('username')
61         password = request.POST.get('password')
62         if username == 'jason' and password == '123':
63 
64             # 獲取用戶上一次想要訪問的url
65             target_url = request.GET.get('next')  # 這個結果多是None
66             if target_url:
67                 obj = redirect(target_url)
68             else:
69                 # 保存用戶登錄狀態
70                 obj = redirect('/home/')
71             # 讓瀏覽器記錄cookie數據
72             obj.set_cookie('username', 'jason666')
73             """
74             瀏覽器不僅僅會幫你存
75             並且後面每次訪問你的時候還會帶着它過來
76             """
77             # 跳轉到一個須要用戶登錄以後才能看的頁面
78             return obj
79     return render(request,'login.html')
80 
81 
82 @login_auth
83 def home(request):
84     # 獲取cookie信息 判斷你有沒有
85     # if request.COOKIES.get('username') == 'jason666':
86     #     return HttpResponse("我是home頁面,只有登錄的用戶才能進來喲~")
87     # # 沒有登錄應該跳轉到登錄頁面
88     # return redirect('/login/')
89     return HttpResponse("我是home頁面,只有登錄的用戶才能進來喲~")
90 
91 
92 @login_auth
93 def logout(request):
94     obj = redirect('/app01/login/')
95     obj.delete_cookie('username')
96     return obj
 1 from django.shortcuts import render, HttpResponse, redirect
 2 
 3 # Create your views here.
 4 
 5 from app01 import models
 6 
 7 
 8 def login_auth(func):
 9     def wrapper(request, *args, **kwargs):
10         print(request.path)
11         print(request.path_info)
12         print(request.get_full_path())
13         target_url = request.get_full_path()
14         if request.COOKIES.get('username'):
15             return func(request, *args, **kwargs)
16         else:
17             return redirect('/app01/login/?next=%s'%target_url)
18 
19     return wrapper
20 
21 
22 @login_auth
23 def home(request):
24     return HttpResponse('歡迎來到app01_home頁面')
25 
26 
27 def login(request):
28     if request.method == 'POST':
29         username = request.POST.get('username')
30         password = request.POST.get('password')
31         if username == 'jason' and password == '123':
32             print(request.GET.get('next'))
33             target_url = request.GET.get('next')
34             if target_url:
35                 obj = redirect(target_url)
36             else:
37                 obj = redirect('/app01/home/')
38             obj.set_cookie('username', 'jason666')
39             return obj
40         else:
41             return HttpResponse('帳號密碼錯誤')
42     return render(request, 'login.html')
43 
44 
45 @login_auth
46 def logout(request):
47     obj = redirect('/app01/login/')
48     obj.delete_cookie('username')
49     return obj
50 
51 
52 @login_auth
53 def index(request):
54     return HttpResponse('歡迎來到app01_Index頁面')
cookie版本登陸認證

cookie其餘方法及參數

獲取Cookie

request.COOKIES['key']
request.get_signed_cookie(key, default=RAISE_ERROR, salt='', max_age=None)


參數:

default: 默認值
salt: 加密鹽
max_age: 後臺控制過時時間



設置Cookie

rep = HttpResponse(...)
rep = render(request, ...)

rep.set_cookie(key,value,...)
rep.set_signed_cookie(key,value,salt='加密鹽', max_age=None, ...)



參數:

key, 鍵
value='', 值
max_age=None, 超時時間
expires=None, 超時時間(IE requires expires, so set it if hasn't been already.)
path='/', Cookie生效的路徑,/ 表示根路徑,特殊的:根路徑的cookie能夠被任何url的頁面訪問
domain=None, Cookie生效的域名
secure=False, https傳輸
httponly=False 只能http協議傳輸,沒法被JavaScript獲取(不是絕對,底層抓包能夠獲取到也能夠被覆蓋)


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

Session操做

 1 """
 2 session數據是保存在服務端的(存?),給客戶端返回的是一個隨機字符串
 3     sessionid:隨機字符串
 4     
 5 1.在默認狀況下操做session的時候須要django默認的一張django_session表
 6     數據庫遷移命令
 7         django會本身建立不少表    django_session就是其中的一張
 8         
 9 
10 django默認session的過時時間是14天
11     可是你也能夠人爲的修改它
12     
13 
14 設置session    
15 request.session['key'] = value
16 
17 獲取session
18 request.session.get('key')
19 
20 設置過時時間
21 request.session.set_expiry()
22     括號內能夠放四種類型的參數
23         1.整數                        多少秒
24         2.日期對象               到指定日期就失效
25         3.0                                一旦當前瀏覽器窗口關閉馬上失效
26         4.不寫                        失效時間就取決於django內部全局session默認的失效時間
27 
28 清除session    
29     request.session.delete()  # 只刪服務端的 客戶端的不刪
30     request.session.flush()  # 瀏覽器和服務端都清空(推薦使用)
31 
32 
33 session是保存在服務端的 可是session的保存位置能夠有多種選擇
34     1.MySQL
35     2.文件
36     3.redis
37     4.memcache
38     ...
39     
40 
41 django_session表中的數據條數是取決於瀏覽器的
42     同一個計算機上(IP地址)同一個瀏覽器只會有一條數據生效
43     (當session過時的時候可能會出現多條數據對應一個瀏覽器,可是該現象不會持續好久,內部會自動識別過時的數據清除 你也能夠經過代碼清除)
44     
45     主要是爲了節省服務端數據庫資源
46 """
47 
48 request.session['hobby'] = 'girl'
49     """
50     內部發送了那些事
51         1.django內部會自動幫你生成一個隨機字符串
52         2.django內部自動將隨機字符串和對應的數據存儲到django_session表中
53             2.1先在內存中產生操做數據的緩存
54             2.2在響應結果django中間件的時候才真正的操做數據庫
55         3.將產生的隨機字符串返回給客戶端瀏覽器保存
56     """
57 request.session.get('hobby')
58     """
59     內部發送了那些事
60         1.自動從瀏覽器請求中獲取sessionid對應的隨機字符串
61         2.拿着該隨機字符串去django_session表中查找對應的數據
62         3.
63             若是比對上了 則將對應的數據取出並以字典的形式封裝到request.session中
64             若是比對不上 則request.session.get()返回的是None
65     """
66   
67   
68 # 利用session實現登錄驗證
 1 from django.shortcuts import render, HttpResponse, redirect
 2 
 3 
 4 # Create your views here.
 5 
 6 
 7 def login_auth(func):
 8     def wrapper(request, *args, **kwargs):
 9         target_url = request.get_full_path()
10         if request.session.get('jason'):
11             return func(request, *args, **kwargs)
12         else:
13             return redirect('/app02/login/?next=%s'%target_url)
14 
15     return wrapper
16 
17 
18 def login(request):
19     if request.method == 'POST':
20         username = request.POST.get('username')
21         password = request.POST.get('password')
22         if username == 'jason' and password == '123':
23             target_url = request.GET.get('next')
24             if target_url:
25                 obj = redirect(target_url)
26             else:
27                 obj = redirect('/app02/home/')
28             request.session['jason'] = 'haha6666'
29             request.session.set_expiry(30)
30             return obj
31         else:
32             HttpResponse('帳號或密碼錯誤')
33     return render(request, 'login.html')
34 
35 
36 @login_auth
37 def home(request):
38     return HttpResponse('歡迎來到app_02home頁面')
39 
40 
41 @login_auth
42 def index(request):
43     return HttpResponse('歡迎來到app_02index頁面')
44 
45 
46 @login_auth
47 def logout(request):
48     request.session.flush()
49     return redirect('/app02/login/')
session版本登陸認證

django中的session方法

# 獲取、設置、刪除Session中數據
request.session['k1']
request.session.get('k1',None)
request.session['k1'] = 123
request.session.setdefault('k1',123) # 存在則不設置
del request.session['k1']


# 全部 鍵、值、鍵值對
request.session.keys()
request.session.values()
request.session.items()
request.session.iterkeys()
request.session.itervalues()
request.session.iteritems()

# 會話session的key
request.session.session_key

# 將全部Session失效日期小於當前日期的數據刪除
request.session.clear_expired()

# 檢查會話session的key在數據庫中是否存在
request.session.exists("session_key")

# 刪除當前會話的全部Session數據
request.session.delete()
  
# 刪除當前的會話數據並刪除會話的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失效策略。

django中的session配置

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,默認修改以後才保存(默認)
django中的session配置

CBV如何添加裝飾器

 1 from django.views import View
 2 from django.utils.decorators import method_decorator
 3 """
 4 CBV中django不建議你直接給類的方法加裝飾器
 5 不管該裝飾器能都正常給你 都不建議直接加
 6 """
 7 
 8 # @method_decorator(login_auth,name='get')  # 方式2(能夠添加多個針對不一樣的方法加不一樣的裝飾器)
 9 # @method_decorator(login_auth,name='post')
10 class MyLogin(View):
11     @method_decorator(login_auth)  # 方式3:它會直接做用於當前類裏面的全部的方法
12     def dispatch(self, request, *args, **kwargs):
13         return super().dispatch(request,*args,**kwargs)
14     # @method_decorator(login_auth)  # 方式1:指名道姓
15     def get(self,request):
16         return HttpResponse("get請求")
17 
18     def post(self,request):
19         return HttpResponse('post請求')

今日測驗

1 """
2 1.什麼是cookie和session,你能描述一下它們的由來和工做機制嗎(切勿糊弄,敷衍了事)
3 2.django中如何操做cookie和session,請寫出儘可能多的操做方法,並針對session的操做
4 方法詳細內部發生的事情,django默認的session失效時間是多久(切勿糊弄,敷衍了事)
5 3.面相對象中的__init__和__new__的區別是什麼,利用__new__能夠實現什麼
6 4.如何給CBV添加裝飾器,列舉你所知道的幾種方式
7 """

今日內容回顧

forms組件源碼

 1 #入口:form_obj.is_valid()
 2 
 3 # 校驗字段和鉤子函數的執行
 4 
 5 # 報錯提示 其實能夠有兩種方式(針對局部鉤子函數)
 6   1.self.add_error()
 7   2.raise ValidationError()
 8 
 9 """
10 python源碼裏面使用最頻繁的其實就是反射
11 """
forms組件源碼

cookie與session

 1 # cookie與session產生緣由
 2         因爲http協議是無狀態的
 3 
 4 # cookie概念
 5     服務端設置保存在客戶端瀏覽器上的鍵值對(只要符合前面的定義均可以叫cookie)
 6     cookie雖然是服務端設置的可是瀏覽器能夠選擇不保存
 7   
 8 # session概念
 9     存儲在服務端上的鍵值對(用來標識當前用戶)    須要基於cookie才能工做
10   其實大部分的保存狀態的實現都須要基於cookie來作
11 
12 # 在web領域沒有絕對的安全
13     基本上防護措施都須要程序員本身寫代碼完善,而且以內完善無法杜絕
cookie與session

django操做cookie

 1 # 須要藉助於HttpResponse對象
 2 
 3 # 設置cookie
 4 obj.set_cookie(key,value)  
 5 # 超時時間
 6 obj.set_cookie(key,value,max_age/expires)  
 7     expires  針對IE須要用這個參數              數字是以秒爲單位
 8 # 加鹽
 9 obj.set_signed_cookie(key,value,salt='')
10 # 獲取
11 request.COOKIES.get(key)
12 request.get_signed_cookie(key,salt='')
13 # 刪除
14 obj.delete_cookie(key)
15 
16 """
17 校驗用戶是否登錄才能訪問視圖函數的裝飾器
18     可以記錄用戶在沒有登錄以前想要訪問的頁面,登錄以後跳轉到對應的頁面
19     request.path
20     request.path_info
21     request.get_full_path()
22 """
django操做cookie

django操做session

 1 """
 2 1.session是存儲在服務端的 django默認狀況下是須要藉助於django_session表
 3 來存儲數據 也就意味着若是你想要操做session那麼必須先執行數據庫遷移命令讓
 4 django先把django_session表建立出來(no such table:django_session)
 5 
 6 2.django默認的session過時時間是14天
 7 
 8 3.session存儲在服務端 能夠有不少地方存儲
 9     1.表
10     2.文件
11     3.緩存
12     4.其餘
13     ...
14 """
15 # 設置
16 request.session[key] = value
17     """
18     三件事
19     """
20 # 獲取
21 request.session.get(key)
22     """
23     三件事
24     """
25 # 刪除
26 request.session.delete()
27 request.session.flush()
28 # 設置超時時間
29 request.session.set_expiry()
30     1.數字                                                            秒數
31   2.datetime/timedelta格式                        日期格式
32   3.None                                                         參加全局失效策略
33   4.0                                                                 窗口關閉即失效
34 
35 """
36 基於session實現用戶登錄
37 
38 有時候若是多個視圖函數都須要使用到一些數據的話,你也能夠考慮將該數據存儲到django_session表中,方便後續的使用
39     eg:
40         登錄驗證碼(bbs做業會涉及到)
41 """
django操做session

CBV如何添加裝飾器

 1 """
 2 django針對CBV添加裝飾器須要你導入一個模塊
 3 """
 4 from django.utils.decorators import method_decorator
 5 
 6 # 第一種  
 7 class MyCBV(View):
 8   def get(self,request):
 9     return HttpResponse()
10   
11   @method_decorator(login_auth)
12      def post(self,request):
13     return HttpResponse()
14   
15 #  第二種
16 @method_decorator(login_auth,name='post')
17 @method_decorator(index_de,name='get')
18 class MyCBV(View):
19   def get(self,request):
20     return HttpResponse()
21  
22      def post(self,request):
23     return HttpResponse()
24 
25 # 第三種
26 class MyCBV(View):
27   @method_decorator(login_auth)
28   def dispatch(self,request,*args,**kwargs):
29     """
30     看CBV源碼能夠得出 CBV裏面全部的方法在執行以前都須要先通過
31     dispatch方法(該方法你能夠當作是一個分發方法)
32     """
33     return super().dispatch(request,*args,**kwargs)
34     
35   def get(self,request):
36     return HttpResponse()
37  
38      def post(self,request):
39     return HttpResponse()
CBV如何添加裝飾器

做業

"""
1.整理今日內容到博客
2.利用session實現登錄驗證
3.複習django階段所學全部知識點,好好整理回顧(後面沒時間了)
4.預習內容:
    https://www.cnblogs.com/Dominic-Ji/p/10881214.html
    
    django中間件
    auth模塊
"""
相關文章
相關標籤/搜索