day69-form源碼,cookies與session

forms組件源碼

"""
切入點:
    form_obj.is_valid()
"""
def is_valid(self):
        """
        Returns True if the form has no errors. Otherwise, False. If errors are
        being ignored, returns False.
        """
   return self.is_bound and not self.errors
   # 若是is_valid要返回True的話 那麼self.is_bound要爲True self.errors要爲Flase
  
  
self.is_bound = data is not None or files is not None  # 只要你傳值了確定爲True


@property
def errors(self):
        "Returns an ErrorDict for the data provided for the form"
        if self._errors is None:
            self.full_clean()
        return self._errors

# forms組件全部的功能基本都出自於該方法
def full_clean(self):
      self._clean_fields()  # 校驗字段 + 局部鉤子
    self._clean_form()  # 全局鉤子
    self._post_clean()  

cookie與session

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


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

Cookie操做

# 雖然cookie是服務端告訴客戶端瀏覽器須要保存內容
# 可是客戶端瀏覽器能夠選擇拒絕保存 若是禁止了 那麼 只要是須要記錄用戶狀態的網站登錄功能都沒法使用了

# 視圖函數的返回值
return HttpResponse()
return render()
return redirect()


obj1 = HttpResponse()
# 操做cookie
return obj1

obj2 = render()
# 操做cookie
return obj2

obj3 = redirect()
# 操做cookie
return obj3
# 若是你想要操做cookie,你就不得不利用obj對象


"""
設置cookie
    obj.set_cookie(key,value)
獲取cookie
    request.COOKIES.get(key)
在設置cookie的時候能夠添加一個超時時間
    obj.set_cookie('username', 'jason666',max_age=3,expires=3)
    
    max_age
    expires
        二者都是設置超時時間的 而且都是以秒爲單位
        須要注意的是 針對IE瀏覽器須要使用expires
主動刪除cookie(註銷功能)
    
    
"""
# 咱們完成一個真正的登錄功能
# 校驗用戶是否登錄的裝飾器
"""
用戶若是在沒有登錄的狀況下想訪問一個須要登錄的頁面
那麼先跳轉到登錄頁面 當用戶輸入正確的用戶名和密碼以後
應該跳轉到用戶以前想要訪問的頁面去 而不是直接寫死
"""
def login_auth(func):
    def inner(request,*args,**kwargs):
        # print(request.path_info)
        # print(request.get_full_path())  # 可以獲取到用戶上一次想要訪問的url
        target_url = request.get_full_path()
        if request.COOKIES.get('username'):
            return func(request,*args,**kwargs)
        else:
            return redirect('/login/?next=%s'%target_url)
    return inner

def login(request):
    if request.method == 'POST':
        username = request.POST.get('username')
        password = request.POST.get('password')
        if username == 'jason' and password == '123':

            # 獲取用戶上一次想要訪問的url
            target_url = request.GET.get('next')  # 這個結果多是None
            if target_url:
                obj = redirect(target_url)
            else:
                # 保存用戶登錄狀態
                obj = redirect('/home/')
            # 讓瀏覽器記錄cookie數據
            obj.set_cookie('username', 'jason666')
            """
            瀏覽器不僅僅會幫你存
            並且後面每次訪問你的時候還會帶着它過來
            """
            # 跳轉到一個須要用戶登錄以後才能看的頁面
            return obj
    return render(request,'login.html')


@login_auth
def home(request):
    # 獲取cookie信息 判斷你有沒有
    # if request.COOKIES.get('username') == 'jason666':
    #     return HttpResponse("我是home頁面,只有登錄的用戶才能進來喲~")
    # # 沒有登錄應該跳轉到登錄頁面
    # return redirect('/login/')
    return HttpResponse("我是home頁面,只有登錄的用戶才能進來喲~")

session操做

"""
session數據是保存在服務端的(存?),給客戶端返回的是一個隨機字符串
    sessionid:隨機字符串
    
1.在默認狀況下操做session的時候須要django默認的一張django_session表
    數據庫遷移命令
        django會本身建立不少表    django_session就是其中的一張
        

django默認session的過時時間是14天
    可是你也能夠人爲的修改它
    

設置session    
request.session['key'] = value

獲取session
request.session.get('key')

設置過時時間
request.session.set_expiry()
    括號內能夠放四種類型的參數
        1.整數                        多少秒
        2.日期對象               到指定日期就失效
        3.0                                一旦當前瀏覽器窗口關閉馬上失效
        4.不寫                        失效時間就取決於django內部全局session默認的失效時間

清除session    
    request.session.delete()  # 只刪服務端的 客戶端的不刪
    request.session.flush()  # 瀏覽器和服務端都清空(推薦使用)


session是保存在服務端的 可是session的保存位置能夠有多種選擇
    1.MySQL
    2.文件
    3.redis
    4.memcache
    ...
    

django_session表中的數據條數是取決於瀏覽器的
    同一個計算機上(IP地址)同一個瀏覽器只會有一條數據生效
    (當session過時的時候可能會出現多條數據對應一個瀏覽器,可是該現象不會持續好久,內部會自動識別過時的數據清除 你也能夠經過代碼清除)
    
    主要是爲了節省服務端數據庫資源
"""

request.session['hobby'] = 'girl'
    """
    內部發送了那些事
        1.django內部會自動幫你生成一個隨機字符串
        2.django內部自動將隨機字符串和對應的數據存儲到django_session表中
            2.1先在內存中產生操做數據的緩存
            2.2在響應結果django中間件的時候才真正的操做數據庫
        3.將產生的隨機字符串返回給客戶端瀏覽器保存
    """
request.session.get('hobby')
    """
    內部發送了那些事
        1.自動從瀏覽器請求中獲取sessionid對應的隨機字符串
        2.拿着該隨機字符串去django_session表中查找對應的數據
        3.
            若是比對上了 則將對應的數據取出並以字典的形式封裝到request.session中
            若是比對不上 則request.session.get()返回的是None
    """
  
  
# 利用session實現登錄驗證

CBV如何添加裝飾器

from django.views import View
from django.utils.decorators import method_decorator
"""
CBV中django不建議你直接給類的方法加裝飾器
不管該裝飾器能都正常給你 都不建議直接加
"""

# @method_decorator(login_auth,name='get')  # 方式2(能夠添加多個針對不一樣的方法加不一樣的裝飾器)
# @method_decorator(login_auth,name='post')
class MyLogin(View):
    @method_decorator(login_auth)  # 方式3:它會直接做用於當前類裏面的全部的方法
    def dispatch(self, request, *args, **kwargs):
        return super().dispatch(request,*args,**kwargs)
    # @method_decorator(login_auth)  # 方式1:指名道姓
    def get(self,request):
        return HttpResponse("get請求")

    def post(self,request):
        return HttpResponse('post請求')
相關文章
相關標籤/搜索