Django之cookie與session、中間件

cookie與session

爲何會有cookie和session

因爲HTTP協議是無狀態的,沒法記住用戶是誰,這樣咱們在每一次登錄的時候,都要從新輸入密碼,甚至若是不設置cookie,網頁可能都請求不了前端

保存在客戶端瀏覽器上的鍵值對python

服務端設置在客戶端瀏覽器上的鍵值對,也就意味着瀏覽器其實能夠拒絕服務端的命令。默認狀況下,瀏覽器都是直接讓服務端設置鍵值對的面試

在操做開始以前咱們須要對三板斧進行變形ajax

obj1 = HttpResponse()
return obj1
obj2 = render()
return obj2
obj3 = redirect()
return obj3

設置cookie

obj1.set_cookie()

獲取cookie

request.COOKIES.get()

刪除cookie

obj1.delete_cookie()

實例:cookie版登陸校驗

直接上代碼:數據庫

def login(request):
    # print(request.path_info)  # 只拿url 不拿get請求攜帶的額外參數
    # print(request.get_full_path())  # 都拿
    
    if request.method == "POST":
        username = request.POST.get('username')
        password = request.POST.get('password')
        if username == 'yjy' and password == '123':
            old_path = request.GET.get('next')
            if old_path:
                # 保存用戶登陸狀態
                obj = redirect(old_path)
            else:
                obj = redirect('/home/')
            obj.set_cookie('name', 'yjy')  # 讓客戶端瀏覽器 記錄一個鍵值對
            # obj.set_cookie('name','jason',max_age=5)  # 讓客戶端瀏覽器 記錄一個鍵值對
            return obj
    return render(request, 'login.html')


from functools import wraps   #裝飾器修復技術
def login_auth(func):
    @wraps(func)
    def inner(request, *args, **kwargs):
        if request.COOKIES.get('name'):
            res = func(request, *args, **kwargs)
            return res
        else:
            target_url = request.path_info
            return redirect('/login/?next=%s' % target_url)
    return inner


@login_auth
def home(request):
    # 校驗用戶是否登陸
    # if request.COOKIES.get('name'):
    #     return HttpResponse('我是主頁 只有登陸了才能看')
    # return redirect('/login/')
    return HttpResponse('我是主頁 只有登陸了才能看')


@login_auth
def index(request):
    return HttpResponse('我是index頁面 也須要用戶登陸以後才能看')


@login_auth
def xxx(request):
    return HttpResponse('xxx頁面 也是須要登陸了以後才能看')


@login_auth
def logout(request):
    obj = redirect('/login/')
    obj.delete_cookie('name')  #註銷以後刪除cookie
    return obj

session

保存在服務器上的鍵值對django

django session默認的過時時間是14天後端

設置session

request.session['key'] = value   #僅僅只會在內存產生一個緩存

三步驟:瀏覽器

  • django內部自動生成了隨機的字符串
  • 在django_session表中存入數據

session_key session_data date
隨機字符串1 數據1 ...
隨機字符串2 數據2 ...
隨機字符串3 數據3 ...緩存

  • 將產生的隨機字符串發送給瀏覽器 讓瀏覽器保存到cookie中(sessionid:隨機字符串)
def set_session(request):
    request.session['username'] = 'yjy'
    request.session.set_expiry(value=0)   #session在關閉瀏覽器後消失
    return HttpResponse("設置session")

獲取session

request.session..get('key')

三步驟:

  • 瀏覽器發送cookie到django後端以後 django會自動獲取到cookie值
  • 拿着隨機字符串去django_session表中比對 是否有對應的數據
  • 若是比對上了 就講隨機字符串所對應的數據 取出賦值給request.session,若是對不上 那麼request.session就是空

session表中的一條記錄針對一個瀏覽器,同一臺電腦上,不一樣的瀏覽器來,纔會有不一樣的記錄

def get_session(request):
    print(request.session.get('username'))
    return HttpResponse('獲取session')

刪除session

delete:刪除服務端的

request.session.delete()

flush:瀏覽器和服務端所有刪除

request.session.flush()
def delete_session(request):
    # request.session.delete()  #刪除服務端的session
    
    request.session.flush()   #兩個端的session都會刪除
    return HttpResponse("刪除session")

session也能夠設置超時時間

request.session.set_expiry(value)
  • value爲整數,session會在數秒後消失(以秒爲單位)
  • value爲 datatime或者timedelta時, session會在這個時間後消失
  • value爲0,session會在關閉瀏覽器後消失
  • value爲None,session會依賴全局session失效策略

實例:session版登陸校驗

後端

from django.shortcuts import render, HttpResponse, redirect


# Create your views here.
def login(request):
    if request.method == 'POST':
        username = request.POST.get('username')
        password = request.POST.get('password')

        if username == "yjy" and password == "123456":
            # 設置session值
            request.session['username'] = username
            # 獲取跳到登錄以前的url
            next_url = request.GET.get("next")
            if next_url:
                return redirect(next_url)
            else:
                return redirect('/index/')
    return render(request, "login.html")

# 裝飾器
from functools import wraps

def check_login(func):
    @wraps(func)
    def inner(request, *args, **kwargs):
        next_url = request.get_full_path()
        print(next_url)
        if request.session.get('username'):
            return func(request, *args, **kwargs)
        else:
            return redirect(f"/login/?next={next_url}")
    #http://127.0.0.1:8000/login/?username=yjy&password=123456
    return inner

@check_login
def index(request):
    # request.session.get("username", None)
    return HttpResponse('我是index頁面 須要用戶登陸以後才能看')

前端:

<form action="" method="post">
    {% csrf_token %}
    <p>username:<input type="text" name="username"></p>
    <p>password:<input type="text" name="password"></p>
    <button><input type="submit"></button>
</form>

最終結果是這樣子的

提交數據以後的顯示

數據庫中session的顯示

django中間件

應用場景

用戶訪問頻率限制
用戶是不是黑名單 白名單
全部用戶登陸校驗
只要是涉及到網址全局的功能 中間件是不二之選

自定義方法

咱們先要作好相應的數據準備

1.新建一個文件夾 裏面新建一個任意名稱的py文件
裏面寫類 固定繼承

from django.utils.deprecation import MiddlewareMixin
class MyMiddle(MiddlewareMixin):
    ...

2.去配置文件註冊到中間件配置中
須要手寫字符串的路徑

'app01.mymiddleware.myaabb.MyMiddle1'
 'app02.mymiddleware.myaabb.MyMiddle2'

process_request:

請求來的時候 會從上往下依次通過每個中間件裏面process_request,一旦裏面返回了HttpResponse對象那麼就再也不日後執行了 會執行同一級別的process_response

def process_request(self,request):
    print('我是第一個自定義中間件裏面的process_request方法')
    return HttpResponse("我是第一個自定義中間件裏面的HttpResponse對象返回值")  # 直接原地返回

process_response:

響應走的時候 會從下往上依次通過每個中間件裏面的process_response

def process_response(self,request,response):  # response就是要返回給用戶的數據
     print("我是第一個自定義中間件裏面的process_response方法")
     return response  #只要有response參數,就必須給他返回

process_view:

路由匹配成功以後,執行視圖函數以前觸發

process_exception:

當視圖函數出現異常(bug)的時候自動觸發

process_template_response:

當視圖函數執行完畢以後而且返回的對象中含有render方法的狀況下才會觸發

django請求生命週期流程圖

中間件以前端操做

form表單

寫form表單以前只須要加上{% csrf_token %}

ajax

第一種: 本身再頁面上先經過{% csrf_token %}獲取到隨機字符串 而後利用標籤查找

data:{'username':'jason','csrfmiddlewaretoken':$('[name="csrfmiddlewaretoken"]').val()},

第二種:

data:{'username':'jason','csrfmiddlewaretoken':'{{ csrf_token }}'},

第三種:拷貝js文件

#這個東西在中間件的官網上拷貝就好了
function getCookie(name) {
    var cookieValue = null;
    if (document.cookie && document.cookie !== '') {
        var cookies = document.cookie.split(';');
        for (var i = 0; i < cookies.length; i++) {
            var cookie = jQuery.trim(cookies[i]);
            // Does this cookie string begin with the name we want?
            if (cookie.substring(0, name.length + 1) === (name + '=')) {
                cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
                break;
            }
        }
    }
    return cookieValue;
}
var csrftoken = getCookie('csrftoken');


function csrfSafeMethod(method) {
  // these HTTP methods do not require CSRF protection
  return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
}

$.ajaxSetup({
  beforeSend: function (xhr, settings) {
    if (!csrfSafeMethod(settings.type) && !this.crossDomain) {
      xhr.setRequestHeader("X-CSRFToken", csrftoken);
    }
  }
});

跨站請求僞造(csrf)

原理:

你寫的form表單中 用戶的用戶名 密碼都會真實的提交給銀行後臺

可是收款人的帳戶卻不是用戶填的 你暴露給用戶的是一個沒有name屬性的input框
你本身提早寫好了一個隱藏的帶有name和value的input框

釣魚網站實例

後端

def transfer(request):
    if request.method == 'POST':
        username = request.POST.get('username')
        target_user = request.POST.get('target_user')
        money = request.POST.get('money')
        print('%s 給 %s轉了%s錢' % (username, target_user, money))
    return render(request, 'transfer.html')

正兒八經網站前端

<form action="" method="post">
    <p>username:<input type="text" name="username"></p>
    <p>target_user:<input type="text" name="target_user"></p>
    <p>money:<input type="text" name="money"></p>
    <input type="submit">
</form>

釣魚網站前端

<form action="http://127.0.0.1:8000/transfer/" method="post">
    <p>username:<input type="text" name="username"></p>
    <p>targer_user:<input type="text"></p>
    <p><input type="text" name="target_user" value="jason" style="display: none"></p>
    <p>money:<input type="text" name="money"></p>
    <input type="submit">
</form>

防釣魚網站策略

只要是用戶想要提交post請求的頁面 我在返回給用戶的時候就提早設置好一個隨機字符串當用戶提交post請求的時候 我會自動先取查找是否有該隨機字符串
若是有 正常提交,若是沒有 直接報403

以上僅僅是一個思路,仍是須要咱們用代碼去實現,具體的實現方法就是在裏面注入中間件。

CBV加裝飾器

先要導入模塊

from django.views.decorators.csrf import csrf_exempt, csrf_protect
from django.utils.decorators import method_decorator

csrf_exempt 兩種裝飾方式

第一種

@method_decorator(csrf_exempt,name='dispatch')
class MyCsrf(View):

第二種

@method_decorator(csrf_exempt)
def dispatch(self, request, *args, **kwargs):
    return super().dispatch(request,*args,**kwargs)
def get(self,request):
    return HttpResponse('hahaha')

其餘裝飾器 三種裝飾方式

第一種

@method_decorator(csrf_protect,name='post')
class MyCsrf(View):

第二種

@method_decorator(csrf_protect)
def dispatch(self, request, *args, **kwargs):
    return super().dispatch(request,*args,**kwargs)
def get(self,request):
    return HttpResponse('hahaha')

第三種

@method_decorator(csrf_protect)
def post(self,request):
   return HttpResponse('post'

每日面試題

python2和python3的區別(至少寫三個)

'''
py2:
>>> print("hello", "world")
('hello', 'world')
py3:
>>> print("hello", "world")
hello world


py2:input_raw()
py3:input()


1/2的結果
py2:返回0
py3:返回0.5


py2:默認編碼ascii
py3:默認編碼utf-8


字符串
py2:unicode類型表示字符串序列,str類型表示字節序列
py3::str類型表示字符串序列,byte類型表示字節序列


py2:函數用關鍵字global聲明某個變量爲全局變量,可是在嵌套函數中,想要給一個變量聲明爲非局部變量是無法實
現的。
py3:新增了關鍵字nonlocal,使得非局部變量成爲可能


py2:
 int() # 整型
 long() # 長整型
py3:沒有long類型,只有int類型


py2:xrange 用法與 range 徹底相同,所不一樣的是生成的不是一個list對象,而是一個生成器。
py3:將之前的range取消了,而將xrange從新命名成了range!因此咱們如今看到的range其實本質仍是xrange~。


py2: iteritems() 用於返回自己字典列表操做後的迭代器【Returns an iterator on allitems(key/value pairs) 】,不佔用額外的內存。
py3: iteritems()方法已經廢除了。在3.x裏用 items()替換iteritems() ,能夠用於 for 來循環遍歷
'''

什麼是可變,什麼是不可變

'''
可變不可變指的是內存中的值是否能夠被改變,
可變:值得改變不會引發內存地址的改變
不可變:值得改變會引發內存地址的改變
不可變類型有數值、字符串、元組;
可變類型則是能夠改變,主要有列表、字典。
'''

m=10,n=5,互換值(至少兩種方式)

'''
t = m  #t=10
m = n  #m=5
n = t  #n=10


m,n = n,m   #交叉賦值
'''
相關文章
相關標籤/搜索