目錄html
因爲HTTP協議是無狀態的,沒法記住用戶是誰,這樣咱們在每一次登錄的時候,都要從新輸入密碼,甚至若是不設置cookie,網頁可能都請求不了前端
保存在客戶端瀏覽器上的鍵值對python
是服務端設置在客戶端瀏覽器上的鍵值對,也就意味着瀏覽器其實能夠拒絕服務端的命令。默認狀況下,瀏覽器都是直接讓服務端設置鍵值對的面試
在操做開始以前咱們須要對三板斧進行變形ajax
obj1 = HttpResponse() return obj1 obj2 = render() return obj2 obj3 = redirect() return obj3
obj1.set_cookie()
request.COOKIES.get()
obj1.delete_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
保存在服務器上的鍵值對django
django session默認的過時時間是14天後端
request.session['key'] = value #僅僅只會在內存產生一個緩存
三步驟:瀏覽器
session_key session_data date
隨機字符串1 數據1 ...
隨機字符串2 數據2 ...
隨機字符串3 數據3 ...緩存
def set_session(request): request.session['username'] = 'yjy' request.session.set_expiry(value=0) #session在關閉瀏覽器後消失 return HttpResponse("設置session")
request.session..get('key')
三步驟:
request.session
,若是對不上 那麼request.session
就是空session
表中的一條記錄針對一個瀏覽器,同一臺電腦上,不一樣的瀏覽器來,纔會有不一樣的記錄
def get_session(request): print(request.session.get('username')) return HttpResponse('獲取session')
delete:刪除服務端的
request.session.delete()
flush:瀏覽器和服務端所有刪除
request.session.flush()
def delete_session(request): # request.session.delete() #刪除服務端的session request.session.flush() #兩個端的session都會刪除 return HttpResponse("刪除session")
request.session.set_expiry(value)
value
爲整數,session
會在數秒後消失(以秒爲單位)value
爲 datatime或者timedelta時, session
會在這個時間後消失value
爲0,session
會在關閉瀏覽器後消失value
爲None,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的顯示
用戶訪問頻率限制
用戶是不是黑名單 白名單
全部用戶登陸校驗
只要是涉及到網址全局的功能 中間件是不二之選
咱們先要作好相應的數據準備
1.新建一個文件夾 裏面新建一個任意名稱的py文件
裏面寫類 固定繼承
from django.utils.deprecation import MiddlewareMixin class MyMiddle(MiddlewareMixin): ...
2.去配置文件註冊到中間件配置中
須要手寫字符串的路徑
'app01.mymiddleware.myaabb.MyMiddle1' 'app02.mymiddleware.myaabb.MyMiddle2'
請求來的時候 會從上往下依次通過每個中間件裏面process_request
,一旦裏面返回了HttpResponse
對象那麼就再也不日後執行了 會執行同一級別的process_response
def process_request(self,request): print('我是第一個自定義中間件裏面的process_request方法') return HttpResponse("我是第一個自定義中間件裏面的HttpResponse對象返回值") # 直接原地返回
響應走的時候 會從下往上依次通過每個中間件裏面的process_response
def process_response(self,request,response): # response就是要返回給用戶的數據 print("我是第一個自定義中間件裏面的process_response方法") return response #只要有response參數,就必須給他返回
路由匹配成功以後,執行視圖函數以前觸發
當視圖函數出現異常(bug)的時候自動觸發
當視圖函數執行完畢以後而且返回的對象中含有render方法的狀況下才會觸發
寫form表單以前只須要加上{% csrf_token %}
第一種: 本身再頁面上先經過{% 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); } } });
原理:
你寫的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
以上僅僅是一個思路,仍是須要咱們用代碼去實現,具體的實現方法就是在裏面注入中間件。
先要導入模塊
from django.views.decorators.csrf import csrf_exempt, csrf_protect from django.utils.decorators import method_decorator
@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'
''' 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 來循環遍歷 '''
''' 可變不可變指的是內存中的值是否能夠被改變, 可變:值得改變不會引發內存地址的改變 不可變:值得改變會引發內存地址的改變 不可變類型有數值、字符串、元組; 可變類型則是能夠改變,主要有列表、字典。 '''
''' t = m #t=10 m = n #m=5 n = t #n=10 m,n = n,m #交叉賦值 '''