Django(六)Session、CSRF、中間件

大綱

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

2、session

一、session與cookie對比

Cookie:保存在用戶瀏覽器端的鍵值對 python

本地能夠修改;若是有敏感信息,能夠被看到。jquery

基於cookie作用戶驗證時,敏感信息不適合放在cookie中
把存儲壓力放到每一個客戶端上,對於服務器端壓力小了。ajax

Session:保存在服務器端的鍵值對redis

服務端:保存鍵值對{'隨機字符串':{……用戶信息……}},經過cookie保存隨機字符串到客戶端上。數據庫

使用session前:先執行 python manage.py makemigrations   , python manage.py migrate,由於默認Django session 保存在數據庫中的django_session表中。django

二、session基本原理及流程

  • session 設置值瀏覽器

    • request.session['is_login'] = True  Django會執行一下操做
   # 生成隨機字符串
   # 寫到用戶瀏覽器cookie
   # 保存到session中
   # 在隨機字符串對應的字典中設置相關內容……

 

  • session 獲取值緩存

    • request.session['is_login']: 執行如下操做
  # 獲取當前用戶的隨機字符串
  # 根據隨機字符串獲取對應信息

 

  • 使用session前,別忘了先生成數據庫   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服務器操做(獲取值、設置值、清空值)

 # 獲取、設置、刪除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失效策略。

 

四、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秒失效。

 

五、session引擎配置(db、cache、file、cookie加密)

Django中默認支持Session,其內部提供了5種類型的Session供開發者使用:

  • 數據庫(默認)
  • 緩存
  • 文件
  • 緩存+數據庫
  • 加密cookie
# 數據庫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'  # 引擎

 

3、CSRF

以前提到的xss攻擊:網站評論裏等容許別人寫js的時候,別人進行的惡意操做。csrf相似。

CSRF的防禦一般有兩種方式,一個是經過Challenge-Response的方式,例如經過Captcha和從新輸入密碼等方式來驗證請求是否僞造,但這會影響用戶體驗,相似銀行付款會採用這樣的方式。另外一種是經過隨機Token的方式,多數Web系統都會採用這種方式,Django也是用的這種。

一、csrf原理-form提交及ajax提交

客戶端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裏看效果。

二、csrf全局與局部應用配置

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);
                }
            });

        }

 

4、中間件生命週期

settings裏的 MIDDLEWARE 都是一個一個的中間件。客戶端請求,先通過一排一排的中間件到達views,以後再經過中間件返回給客戶端。而經過中間件都是調用中間件的某個方法、

一、process_request、process_response

  • process_request:客戶端請求,通過中間件的方法
  • process_response:返回客戶端,通過中間件的方法

下面本身建立一箇中間件

隨便建立一個目錄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。

因此中間件是對全部的請求作統一操做,好比數據校驗、黑名單過濾

二、process_view

以下:每一箇中間件類中中加入以下方法:

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方法,執行這個方法。

 

1、內容回顧

一、基本生命週期

二、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

相關文章
相關標籤/搜索