2、session
一、session與cookie對比
二、session基本原理及流程
三、session服務器操做(獲取值、設置值、清空值)
四、session通用配置(在配置文件中)
五、session引擎配置(db、cache、file、cookie加密)
3、CSRF
一、csrf原理-form提交及ajax提交
二、csrf全局與局部應用配置
4、中間件生命週期
一、process_request、process_response
下面本身建立一箇中間件
二、process_view
三、其餘
1、內容回顧html
Cookie:保存在用戶瀏覽器端的鍵值對 python
本地能夠修改;若是有敏感信息,能夠被看到。jquery
基於cookie作用戶驗證時,敏感信息不適合放在cookie中
把存儲壓力放到每一個客戶端上,對於服務器端壓力小了。ajax
Session:保存在服務器端的鍵值對redis
服務端:保存鍵值對{'隨機字符串':{……用戶信息……}}
,經過cookie保存隨機字符串到客戶端上。數據庫
使用session前:先執行 python manage.py makemigrations
, python manage.py migrate
,由於默認Django session 保存在數據庫中的django_session表中。django
session 設置值瀏覽器
request.session['is_login'] = True
Django會執行一下操做# 生成隨機字符串 # 寫到用戶瀏覽器cookie # 保存到session中 # 在隨機字符串對應的字典中設置相關內容……
session 獲取值緩存
request.session['is_login']:
執行如下操做# 獲取當前用戶的隨機字符串 # 根據隨機字符串獲取對應信息
python manage.py migrate
urls.py服務器
url(r'^login/', views.login), url(r'^index/', views.index), url(r'^logout/$', views.logout),
views.py
def login(request): if request.method == "GET": return render(request,'login.html') elif request.method == "POST": user = request.POST.get('user') pwd = request.POST.get('pwd') if user == 'root' and pwd == "123": # session中設置值 # 生成隨機字符串 # 寫到用戶瀏覽器cookie # 保存到session中 # 在隨機字符串對應的字典中設置相關內容…… request.session['username'] = user request.session['is_login'] = True if request.POST.get('rmb',None) == '1': # 超時時間 request.session.set_expiry(10) return redirect('/index/') else: return render(request,'login.html') def index(request): # 獲取當前用戶的隨機字符串 # 根據隨機字符串獲取對應信息 if request.session.get('is_login',None): return HttpResponse(request.session['username']) else: return HttpResponse("請登陸……") def logout(request): # del request.session['username'] request.session.clear() # 清除session,註銷 return redirect('/login/')
login.html
<body> <form action="/login/" method="POST"> <input type="text" name="user" /> <input type="text" name="pwd" /> <input type="checkbox" name="rmb" value="1" /> 10秒免登陸 <input type="submit" value="提交" /> </form> </body>>
index.html
<body> <h1>歡迎登陸:{{ username }}, {{ request.session.username }}</h1> <!---------- 這裏不用使用後臺模板傳值,使用session也能獲取到用戶名 --------------> <a href="/logout/">註銷</a> </body>
# 獲取、設置、刪除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的隨機字符串 request.session.session_key # 將全部Session失效日期小於當前日期的數據刪除 request.session.clear_expired() # 檢查 用戶session的隨機字符串 在數據庫中是否存在 request.session.exists("session_key") # 刪除當前用戶的全部Session數據 request.session.delete("session_key") request.session.clear() # 比delete用法更簡單,註銷的時候可使用 # 設置超時時間 (默認session超時時間是兩週) request.session.set_expiry(value) # * 若是value是個整數,session會在些秒數後失效。 # * 若是value是個datatime或timedelta,session就會在這個時間後失效。 # * 若是value是0,用戶關閉瀏覽器session就會失效。 # * 若是value是None,session會依賴全局session失效策略。
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,默認修改以後才保存(默認) # 這個好。settings裏設爲true,超時時間按照最後一次客戶端請求計算,如上按照最後一次請求以後10秒失效。
Django中默認支持Session,其內部提供了5種類型的Session供開發者使用:
# 數據庫Session SESSION_ENGINE = 'django.contrib.sessions.backends.db' # 引擎(默認) # 緩存Session SESSION_ENGINE = 'django.contrib.sessions.backends.cache' # 引擎 SESSION_CACHE_ALIAS = 'default' # 使用的緩存別名(默認內存緩存,也能夠是memcache),此處別名依賴緩存的設置 # 鏈接memcache 的配置,緩存部分會提到。不支持redis,連它須要安裝插件 # 文件Session SESSION_ENGINE = 'django.contrib.sessions.backends.file' # 引擎 SESSION_FILE_PATH = os.path.join(BASE_DIR, 'cache') # 放到cache目錄下 SESSION_FILE_PATH = None # 緩存文件路徑,若是爲None,則使用tempfile模塊獲取一個臨時地址tempfile.gettempdir() # 如:/var/folders/d3/j9tj0gz93dg06bmwxmhh6_xm0000gn/T # 緩存+數據庫Session SESSION_ENGINE = 'django.contrib.sessions.backends.cached_db' # 引擎 # 加密cookie Session (都放到cookie裏面,只是作了加密處理) SESSION_ENGINE = 'django.contrib.sessions.backends.signed_cookies' # 引擎
以前提到的xss攻擊:網站評論裏等容許別人寫js的時候,別人進行的惡意操做。csrf相似。
CSRF的防禦一般有兩種方式,一個是經過Challenge-Response的方式,例如經過Captcha和從新輸入密碼等方式來驗證請求是否僞造,但這會影響用戶體驗,相似銀行付款會採用這樣的方式。另外一種是經過隨機Token的方式,多數Web系統都會採用這種方式,Django也是用的這種。
客戶端get請求時,django會生成隨機字符串給客戶,當客戶端提交form表單的時候,若是沒有隨機字符串,則django不容許,報403錯誤。
form提交數據須要帶隨機字符串過去,Ajax提交也須要帶着過去。ajax帶哪的值?
加上{% csrf_token %}
在html form裏生成了一個,在也生成了一份。瀏覽器審查元素 –> Network –> Cookies 裏也能找到隨機字符串。
因此ajax提交的時候,只須要把cookie裏的隨機字符串拿到,放到請求頭裏面發過去就能夠了
後臺獲取隨機字符串的key,key是什麼值? x-CSRFtoken
login.html
<body> <!-- form 提交 --> <form action="/login/" method="POST"> <!-- 生成 csrf 的隨機字符串 --> <!-- {{ csrf_token }} --> {% csrf_token %} <!--html裏會自動生成隱藏input框--> <input type="text" name="user" /> <input type="text" name="pwd" /> <input type="checkbox" name="rmb" value="1" /> 10秒免登陸 <input type="submit" value="提交" /> <input id="btn" type="button" value="Ajax提交" /> </form> <script src="/static/jquery-1.12.4.js"></script> <script src="/static/jquery.cookie.js"></script> <script> $(function(){ // ajax 提交 $.ajaxSetup({ // 對整個頁面全部的ajax操做作個配置 beforeSend: function(xhr,settings){ // 發送ajax前的操做 xhr.setRequestHeader('X-CSRFtoken', $.cookie('csrftoken')); } }); $('#btn').click(function () { $.ajax({ url: '/login/', type:"POST", data: {'user': 'root', 'pwd': '123'}, // 這種方式加請求頭,每一個操做都加麻煩一些,因此使用上面的 ajaxSetup 里加 // headers: {'X-CSRFtoken': $.cookie('csrftoken')}, success:function(arg){ } }) }); }) </script> </body>
這裏ajax提交,在瀏覽器審查元素、network裏看效果。
settings裏面,容許csrf驗證,那麼就是對全局都進行驗證。若是個別的方法不須要使用,怎麼單一配置?
django爲用戶實現防止跨站請求僞造的功能,經過中間件 django.middleware.csrf.CsrfViewMiddleware
來完成。而對於django中設置防跨站請求僞造功能有分爲全局和局部。
全局:
中間件 django.middleware.csrf.CsrfViewMiddleware
局部:
@csrf_protect
,爲當前函數強制設置防跨站請求僞造功能,即使settings中沒有設置全局中間件。@csrf_exempt
,取消當前函數防跨站請求僞造功能,即使settings中設置了全局中間件。注:from django.views.decorators.csrf import csrf_exempt,csrf_protect
對於ajax中,採用ajaxSetup
方式也是全局都加,好比get方式是不須要的,能夠以下配置
var csrftoken = $.cookie('csrftoken'); function csrfSafeMethod(method) { // these HTTP methods do not require CSRF protection return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method)); } $.ajaxSetup({ beforeSend: function(xhr, settings) { // settings 會獲取到ajax裏面的全部配置 if (!csrfSafeMethod(settings.type) && !this.crossDomain) { xhr.setRequestHeader("X-CSRFToken", csrftoken); } } }); function Do(){ $.ajax({ url:"/app01/test/", data:{id:1}, type:'POST', success:function(data){ console.log(data); } }); }
settings裏的 MIDDLEWARE 都是一個一個的中間件。客戶端請求,先通過一排一排的中間件到達views,以後再經過中間件返回給客戶端。而經過中間件都是調用中間件的某個方法、
隨便建立一個目錄middle,
middle/m.py
from django.utils.deprecation import MiddlewareMixin class Row1(MiddlewareMixin): def process_request(self, request): print("中間件1") def process_response(self, request, response): print("中間件1返回") return response # 參數裏的 response :就是views裏面返回的值,因此要繼續返回一下,不然客戶端收不到數據 from django.shortcuts import HttpResponse class Row2(MiddlewareMixin): def process_request(self, request): print("中間件2") # return HttpResponse("禁止你訪問") def process_response(self, request, response): print("中間件2返回") return response class Row3(MiddlewareMixin): def process_request(self, request): print("中間件3") def process_response(self, request, response): print("中間件3返回") return response
settings.py
MIDDLEWARE = [ 'django.middleware.security.SecurityMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware', 'django.middleware.common.CommonMiddleware', 'django.middleware.csrf.CsrfViewMiddleware', 'django.contrib.auth.middleware.AuthenticationMiddleware', 'django.contrib.messages.middleware.MessageMiddleware', 'django.middleware.clickjacking.XFrameOptionsMiddleware', 'middle.m.Row1', 'middle.m.Row2', 'middle.m.Row3', ]
views.py
def test(request): print("最終返回信息") return HttpResponse("OK")
中間件裏面的參數request裏接受的數據和views裏接受的數據是同樣的,因此從裏面取值能夠作相應的判斷處理,允不容許數據經過。
好比上面的示例:中間件row2,process_request,裏返回數據,則會在同級的process_response裏開始返回數據給客戶端了。
注意:這是在Django1.10版本才這樣的,以前版本:row2返回數據,會在最底部的response開始網上返回數據,這裏是row3。
因此中間件是對全部的請求作統一操做,好比數據校驗、黑名單過濾
以下:每一箇中間件類中中加入以下方法:
class Row1(MiddlewareMixin): def process_request(self, request): print("中間件1") def process_view(self, request, view_func, view_func_args, view_func_kwargs): # view_func 對應 views函數,view_func_args、kwargs 對應 views裏的參數、 print("中間件1view") def process_response(self, request, response): print("中間件1返回") return response
請求順序以下:用戶請求 –> 每一箇中間件的request –> 到達urls路由匹配,匹配成功後 –> 折回每一箇中間件的view –> views –> 經過response返回
def process_exception(self, request, exception): if isinstance(exception, ValueError): return HttpResponse("出現異常") # 異常處理 views函數裏出錯了,執行這裏,如views裏 int('lgeng')
views函數若是出現異常,返回會找exception方法,一級一級往上找,若是有處理返回,若是都沒有處理就直接返回報錯了。
process_template_response(self,request,response) # 若是views中的函數返回的對象中,具備render方法,執行這個方法。
一、基本生命週期
二、URL
/index/ index /list/(\d+) index /list/(\d+) name='li' index /list/(\d+) include index
三、views
# 全部內容的原生值 request.body # 全部的post請求,都會放到body裏面傳過去 request.POST # 從request.body中提取 request.GET # 從request.body中提取 request.FILES request.xxxx.getlist # 請求頭內容 request.Meta request.method(POST,GET,PUT) request.path_info request.COOKIES …… # 返回數據 ######### return HttpResponse # 支持返回字符串 和 bytes類型 return render # 渲染頁面 return redirect # 跳轉 # 返回cookie ## response = HttpResponse('ok') response.set_cookie() return response # 把cookie,放到響應頭裏面,客戶端瀏覽器去響應頭裏面獲取。。因此也能設置響應頭內容 response['name'] = 'lgeng'
四、Model操做(原生Sql也能夠)
# 表內容操做: models.TB.objects.create() obj = models.TB(..) obj.save() models.TB.objects.all()[7:10] # 切片 models.TB.objects.update() models.TB.objects.filter() models.TB.objects.delete models.TB.objects.values models.TB.objects.values_list models.TB.objects.get models.TB.objects.filter().update() models.TB.objects.filter().first() models.TB.objects.filter(**{}).count() models.TB.objects.filter(雙下劃線跨表) models.TB.objects.filter(id__gte=1) models.TB.objects.exclude(id__lt=1) models.TB.objects.filter(id_in=[1,2,3]) # id__in # 多對多 obj.set obj.add([1,2,3]) obj.add(1,2,3) obj.remove([1,2,3]) obj.clear() models.TB.objects.all() [obj,obj] obj.fk.name models.TB.objects.all().order_by('') models.TB.objects.distinct() ## 跨表操做 ########### class A: name ... # 而A表操做B表,經過表名+‘_set’ --> b_set class B: caption ... fk = ForignKey(A) # B表操做A表,經過 fk.
五、模板語言
# 基本操做 def func(request): return render(request,'index.html',{'val':[1,2,3]}) # index.html 裏 <h1>{{ val.0 }}</h1> # 繼承 extends "layout.html" # include 組件 # simpli_tag, filter
轉載請務必保留此出處:http://www.cnblogs.com/lgeng/articles/7365891.html
<!-- END -->
《版本說明》: 本文轉自 -- http://blog.csdn.net/fgf00/article/details/54299199