1. 程式人生 > 其它 >59.django 中間鍵及相關知識點

59.django 中間鍵及相關知識點

 

    中介軟體
        中介軟體就類似於是django的門戶,django的中介軟體是設計比較完善的
            1.django預設有七個中介軟體
                session
                csrf
                authenticate
            2.django還支援使用者自定義自己的中介軟體並且暴露給使用者五個可以自定義的方法
                需要掌握的方法
                    1.process_request
                        請求來的時候會從上往下依次經過settings配置檔案註冊了的中介軟體裡面的該方法,如果沒有執行跳過執行下一個
                        該方法可以實現對使用者身份的校驗,訪問頻率的限制,使用者許可權的校驗...
                        注意:如果你在該方法中直接返回了HttpResponse物件,那麼就不會再往後執行
                            會跳到同級別的process_response方法 從下往上依次執行返回
                    
2.process_response 響應走的時候會從下往上依次經過settings配置檔案註冊了中介軟體裡面的該方法 該方法有一個形參response你再不攔截返回的過程 應該將該形參返回 注意:該方法可以幫你實現快取機制 需要了解的方法 3.process_view 路由匹配成功之後執行檢視函式之前觸發
4.process_exception 檢視函數出現bug的時候 會觸發 5.process_templates_response 檢視函式返回的物件中包含了render方法 obj = HttpResponse('aaa') def render(): return HttpResponse('使用者能夠看到的結果
') obj.render = render return obj 如何自定義中介軟體 新建一個資料夾(放在全域性或者應用內) 寫一個類繼承MiddlewareMiXin類 裡面書寫方面的五個方法任意幾個即可 一定要在setting檔案註冊 必須要會的:自己能夠畫出一個特別特別完整的django請求生命週期流程圖 csrf跨站請求偽造 釣魚網站 如何區分當前使用者朝我們網站傳送的請求頁面是否是我們本網站給的 1.如何避免csrf校驗問題 form表單內 {% csrf_token %} # 自動生成一個name屬性值為csrfmiddlewaretoken value值為隨機字串的一個input標籤並且是隱藏的 ajax 1.通過標籤查詢獲取屬性的方式 $('[name=csrfmiddlewaretoken]').val() 2.直接利用模板語法提供的快捷方式 '{{ csrf_token }}' 3.參考官方文件推薦 自定義js檔案 自動獲取並傳遞csrf校驗 通過script標籤直接引入 即可解決csrf校驗的問題 csrf裝飾器相關 csrf_exempt就他不校驗,csrf_protect就他校驗 method_decorator(CBV) 在給CBV裝飾的時候,上面兩個裝飾器有一點不同 csrf_protect有三種方式 1.利用method_decorator直接加在方法上 2.還可以直接加在類上面 同name指定 3.加在dispatch方法上 csrf_exempt只有兩種 1.只能加在dispatch方法上 針對其他的裝飾 都和csrf_protect一致 都有三種方式 auth認證 使用者相關的模組 from django.contrib import auth 1.查詢使用者是否存在 auth.authenticate(username=username,password=password) 該方法會有一個返回值 返回值要麼是物件要麼是None 2.記錄使用者狀態 auth.login(request,user_obj) 該方法的優點在於 知道執行了 就可以在任意位置通過request.user獲取到當前登入物件 3.獲取使用者物件 request.user 使用者登入了直接獲取使用者物件 使用者沒有登入獲取到的匿名使用者 4.如何判斷使用者是否登入 request.user.is_authenticated 返回的結果是布林值 5.登出使用者 auth.logout(request) 等價於request.session.flush() 6.修改密碼 確認舊密碼是否正確 request.user.check_password(old_password) 該方法也會有一個返回值 並且是布林值型別 修改密碼 request.user.set_password(new_password) request.user.save() 7.校驗使用者是否登入裝飾器 login_required 該裝飾在不傳參的情況下 如果使用者沒有登入 會預設跳到一個不是我們自己寫的登陸頁面(報錯) 你可以通過配置 來讓它跳到你自己的登陸配置 區域性配置 login_required(login_url='/login/') 全域性配置 settings檔案中 LOGIN_URL = '/login/' 8.註冊使用者 from django.contrib.auth.models import User 不能再直接呼叫create方法 因為該方法儲存的密碼是明文的 User.objects.create_user() User.objects.create_superuser() 9.自定義模型表 自定義模型類一定要繼承AbstractUser from django.contrib.auth.models import AbstractUser class User(AbstractUser): # 不要跟原來表中已經有的欄位衝突 phone = ... avatar = ... create_time = ... 一定要去配置檔案中註冊 AUTH_USER_MODELS = '應用名.類名' 設計思想(******) 參考django中介軟體,後面的所學的restframework等
內容回顧 總結
今日內容
    django中間鍵

    csrf跨站請求偽造

    auth模組

    settings功能插拔式原始碼

    今日內容
        django中介軟體
            django中介軟體是類似於是django的保安
            請求的時候需要先經過中介軟體才能到達django後端(urls,views,templates,models)
            響應走的時候也需要經過中介軟體才能到達web服務閘道器介面
            自定義-day59 mymiddleware /mdd.py

            django預設的七個中介軟體
                MIDDLEWARE = [
                                'django.middleware.security.SecurityMiddleware',  # 安全相關
                                'django.contrib.sessions.middleware.SessionMiddleware', # session存取相關
                                'django.middleware.common.CommonMiddleware',
                                'django.middleware.csrf.CsrfViewMiddleware',
                                'django.contrib.auth.middleware.AuthenticationMiddleware', # 認證
                                'django.contrib.messages.middleware.MessageMiddleware',
                                'django.middleware.clickjacking.XFrameOptionsMiddleware',
                            ]

            # 1.安全相關的
                class SecurityMiddleware(MiddlewareMixin):
                    def __init__(self, get_response=None):
                        self.sts_seconds = settings.SECURE_HSTS_SECONDS
                        self.sts_include_subdomains = settings.SECURE_HSTS_INCLUDE_SUBDOMAINS
                        self.sts_preload = settings.SECURE_HSTS_PRELOAD
                        self.content_type_nosniff = settings.SECURE_CONTENT_TYPE_NOSNIFF
                        self.xss_filter = settings.SECURE_BROWSER_XSS_FILTER
                        self.redirect = settings.SECURE_SSL_REDIRECT
                        self.redirect_host = settings.SECURE_SSL_HOST
                        self.redirect_exempt = [re.compile(r) for r in settings.SECURE_REDIRECT_EXEMPT]
                        self.get_response = get_response

                    def process_request(self, request):
                        path = request.path.lstrip("/")
                        if (self.redirect and not request.is_secure() and
                                not any(pattern.search(path)
                                        for pattern in self.redirect_exempt)):
                            host = self.redirect_host or request.get_host()
                            return HttpResponsePermanentRedirect(
                                "https://%s%s" % (host, request.get_full_path())
                            )

                    def process_response(self, request, response):
                        if (self.sts_seconds and request.is_secure() and
                                'strict-transport-security' not in response):
                            sts_header = "max-age=%s" % self.sts_seconds
                            if self.sts_include_subdomains:
                                sts_header = sts_header + "; includeSubDomains"
                            if self.sts_preload:
                                sts_header = sts_header + "; preload"
                            response["strict-transport-security"] = sts_header

                        if self.content_type_nosniff and 'x-content-type-options' not in response:
                            response["x-content-type-options"] = "nosniff"

                        if self.xss_filter and 'x-xss-protection' not in response:
                            response["x-xss-protection"] = "1; mode=block"

                        return response

                class CsrfViewMiddleware(MiddlewareMixin):
                        if settings.CSRF_USE_SESSIONS:
                            request.session[CSRF_SESSION_KEY] = request.META['CSRF_COOKIE']
                        else:
                            response.set_cookie(
                                settings.CSRF_COOKIE_NAME,
                                request.META['CSRF_COOKIE'],
                                max_age=settings.CSRF_COOKIE_AGE,
                                domain=settings.CSRF_COOKIE_DOMAIN,
                                path=settings.CSRF_COOKIE_PATH,
                                secure=settings.CSRF_COOKIE_SECURE,
                                httponly=settings.CSRF_COOKIE_HTTPONLY,
                            )
                            # Set the Vary header since content varies with the CSRF cookie.
                            patch_vary_headers(response, ('Cookie',))
                    def process_request(self, request):
                        csrf_token = self._get_token(request)
                        if csrf_token is not None:
                            # Use same token next time.
                            request.META['CSRF_COOKIE'] = csrf_token

                    def process_view(self, request, callback, callback_args, callback_kwargs):
                        if getattr(request, 'csrf_processing_done', False):
                            return None

                        # Wait until request.META["CSRF_COOKIE"] has been manipulated before
                        # bailing out, so that get_token still works
                        if getattr(callback, 'csrf_exempt', False):
                            return None

                        # Assume that anything not defined as 'safe' by RFC7231 needs protection
                        if request.method not in ('GET', 'HEAD', 'OPTIONS', 'TRACE'):
                            if getattr(request, '_dont_enforce_csrf_checks', False):
                                # Mechanism to turn off CSRF checks for test suite.
                                # It comes after the creation of CSRF cookies, so that
                                # everything else continues to work exactly the same
                                # (e.g. cookies are sent, etc.), but before any
                                # branches that call reject().
                                return self._accept(request)

                            if request.is_secure():
                                # Suppose user visits http://example.com/
                                # An active network attacker (man-in-the-middle, MITM) sends a
                                # POST form that targets https://example.com/detonate-bomb/ and
                                # submits it via JavaScript.
                                #
                                # The attacker will need to provide a CSRF cookie and token, but
                                # that's no problem for a MITM and the session-independent
                                # secret we're using. So the MITM can circumvent the CSRF
                                # protection. This is true for any HTTP connection, but anyone
                                # using HTTPS expects better! For this reason, for
                                # https://example.com/ we need additional protection that treats
                                # http://example.com/ as completely untrusted. Under HTTPS,
                                # Barth et al. found that the Referer header is missing for
                                # same-domain requests in only about 0.2% of cases or less, so
                                # we can use strict Referer checking.
                                referer = force_text(
                                    request.META.get('HTTP_REFERER'),
                                    strings_only=True,
                                    errors='replace'
                                )
                                if referer is None:
                                    return self._reject(request, REASON_NO_REFERER)

                                referer = urlparse(referer)

                                # Make sure we have a valid URL for Referer.
                                if '' in (referer.scheme, referer.netloc):
                                    return self._reject(request, REASON_MALFORMED_REFERER)

                                # Ensure that our Referer is also secure.
                                if referer.scheme != 'https':
                                    return self._reject(request, REASON_INSECURE_REFERER)

                                # If there isn't a CSRF_COOKIE_DOMAIN, require an exact match
                                # match on host:port. If not, obey the cookie rules (or those
                                # for the session cookie, if CSRF_USE_SESSIONS).
                                good_referer = (
                                    settings.SESSION_COOKIE_DOMAIN
                                    if settings.CSRF_USE_SESSIONS
                                    else settings.CSRF_COOKIE_DOMAIN
                                )
                                if good_referer is not None:
                                    server_port = request.get_port()
                                    if server_port not in ('443', '80'):
                                        good_referer = '%s:%s' % (good_referer, server_port)
                                else:
                                    # request.get_host() includes the port.
                                    good_referer = request.get_host()

                                # Here we generate a list of all acceptable HTTP referers,
                                # including the current host since that has been validated
                                # upstream.
                                good_hosts = list(settings.CSRF_TRUSTED_ORIGINS)
                                good_hosts.append(good_referer)

                                if not any(is_same_domain(referer.netloc, host) for host in good_hosts):
                                    reason = REASON_BAD_REFERER % referer.geturl()
                                    return self._reject(request, reason)

                            csrf_token = request.META.get('CSRF_COOKIE')
                            if csrf_token is None:
                                # No CSRF cookie. For POST requests, we insist on a CSRF cookie,
                                # and in this way we can avoid all CSRF attacks, including login
                                # CSRF.
                                return self._reject(request, REASON_NO_CSRF_COOKIE)

                            # Check non-cookie token for match.
                            request_csrf_token = ""
                            if request.method == "POST":
                                try:
                                    request_csrf_token = request.POST.get('csrfmiddlewaretoken', '')
                                except IOError:
                                    # Handle a broken connection before we've completed reading
                                    # the POST data. process_view shouldn't raise any
                                    # exceptions, so we'll ignore and serve the user a 403
                                    # (assuming they're still listening, which they probably
                                    # aren't because of the error).
                                    pass

                            if request_csrf_token == "":
                                # Fall back to X-CSRFToken, to make things easier for AJAX,
                                # and possible for PUT/DELETE.
                                request_csrf_token = request.META.get(settings.CSRF_HEADER_NAME, '')

                            request_csrf_token = _sanitize_token(request_csrf_token)
                            if not _compare_salted_tokens(request_csrf_token, csrf_token):
                                return self._reject(request, REASON_BAD_TOKEN)

                        return self._accept(request)

                    def process_response(self, request, response):
                        if not getattr(request, 'csrf_cookie_needs_reset', False):
                            if getattr(response, 'csrf_cookie_set', False):
                                return response

                        if not request.META.get("CSRF_COOKIE_USED", False):
                            return response

                        # Set the CSRF cookie even if it's already set, so we renew
                        # the expiry timer.
                        self._set_token(request, response)
                        response.csrf_cookie_set = True
                        return response


                class AuthenticationMiddleware(MiddlewareMixin):
                    def process_request(self, request):
                        assert hasattr(request, 'session'), (
                            "The Django authentication middleware requires session middleware "
                            "to be installed. Edit your MIDDLEWARE%s setting to insert "
                            "'django.contrib.sessions.middleware.SessionMiddleware' before "
                            "'django.contrib.auth.middleware.AuthenticationMiddleware'."
                        ) % ("_CLASSES" if settings.MIDDLEWARE is None else "")
                        request.user = SimpleLazyObject(lambda: get_user(request))



                django中介軟體中有五個使用者可以自定義的方法
                    需要我們掌握的的方法:
                        1.process_request()
                        2.process_response()方法 # response 響應
                    需要了解的方法
                        3.process_view()
                        4.process_exception() # 例外
                        5.process_template_response()


                    django中介軟體可以用來做什麼(***********************)
                        1.網站全域性的身份校驗,訪問頻率限制,許可權校驗...只要是涉及到全域性的校驗你都可以在中介軟體中完成
                        2.django的中介軟體是所有web框架中 做的最好的


                    需要我們掌握的方法有
                        1.process_request()方法
                            規律
                                1.請求來的時候 會經過每個中介軟體裡面的process_request方法(從上往下)
                                2.如果方法裡面直接返回了HttpResponse物件 那麼會直接返回 不再往下執行
                                ps:flask 框架 不是這樣,他是,無論在哪返回的,都是從頭開始依次執行 process_response()
                                    基於該特點就可以做訪問頻率限制,身份校驗,許可權校驗

                        2.process_response()方法
                            規律
                                1.必須將response形參返回 因為這個形參指代的就是要返回給前端的資料
                                2.響應走的時候 會依次經過每一箇中間件裡面的process_response方法(從下往上)

                    需要了解的方法
                        3.process_view()
                            1.在路由匹配成功執行檢視函式之前 觸發

                        4.process_exception()
                            1.當你的檢視函式報錯時  就會自動執行

                        5.process_template_response()
                            1.當你返回的HttpResponse物件中必須包含render屬性才會觸發
                            def index(request):
                                print('我是index檢視函式')
                                def render():
                                    return HttpResponse('什麼鬼玩意')
                                obj = HttpResponse('index')
                                obj.render = render
                                return obj
                總結:你在書寫中介軟體的時候 只要形參中有repsonse 你就順手將其返回 這個reponse就是要給前端的訊息


                如何自定義我們自己的中介軟體,研究這上面五個方法都有哪些特點
                        1.如果你想讓你寫的中介軟體生效 就必須要先繼承MiddlewareMixin
                        2.在註冊自定義中介軟體的時候 一定要確保路徑不要寫錯


        csrf跨站請求偽造
                釣魚網站
                通過製作一個跟正兒八經的網站一模一樣的頁面,騙取使用者輸入資訊 轉賬交易
                從而做手腳
                    轉賬交易的請求確確實實是發給了中國銀行,賬戶的錢也是確確實實少了
                    唯一不一樣的地方在於收款人賬戶不對
                內部原理
                    在讓使用者輸入對方賬戶的那個input上面做手腳
                    給這個input不設定name屬性,在內部隱藏一個實現寫好的name和value屬性的input框
                    這個value的值 就是釣魚網站受益人賬號

                防止釣魚網站的思路
                    網站會給返回給使用者的form表單頁面 偷偷塞一個隨機字串
                    請求到來的時候 會先比對隨機字串是否一致  如果不一致  直接拒絕(403)

                該隨機字串有以下特點
                    1.同一個瀏覽器每一次訪問都不一樣
                    2.不同瀏覽器絕對不會重複

        1.form表單傳送post請求的時候  需要你做得僅僅書寫一句話
            {% csrf_token %}

        2.ajax傳送post請求 如何避免csrf校驗
            1.現在頁面上寫{% csrf_token %},利用標籤查詢  獲取到該input鍵值資訊
                {'username':'jason','csrfmiddlewaretoken':$('[name=csrfmiddlewaretoken]').val()}
                $('[name=csrfmiddlewaretoken]').val()

            2.直接書寫'{{ csrf_token }}'
                {'username':'jason','csrfmiddlewaretoken':'{{ csrf_token }}'}
                {{ csrf_token }}

            3.你可以將該獲取隨機鍵值對的方法 寫到一個js檔案中,之後只需要匯入該檔案即可
                新建一個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);
                    }
                  }
                });



        1.當你網站全域性都需要校驗csrf的時候 有幾個不需要校驗該如何處理
        2.當你網站全域性不校驗csrf的時候 有幾個需要校驗又該如何處理
            from django.utils.decorators import method_decorator
            from django.views.decorators.csrf import csrf_exempt,csrf_protect
            # 這兩個裝飾器在給CBV裝飾的時候 有一定的區別
            如果是csrf_protect 那麼有三種方式
                # 第一種方式
                # @method_decorator(csrf_protect,name='post')  # 有效的
                class MyView(View):
                    # 第三種方式
                    # @method_decorator(csrf_protect)
                    def dispatch(self, request, *args, **kwargs):
                        res = super().dispatch(request, *args, **kwargs)
                        return res

                    def get(self,request):
                        return HttpResponse('get')
                    # 第二種方式
                    # @method_decorator(csrf_protect)  # 有效的
                    def post(self,request):
                        return HttpResponse('post')

            如果是csrf_exempt 只有兩種(只能給dispatch裝)   特例
            @method_decorator(csrf_exempt,name='dispatch')  # 第二種可以不校驗的方式
            class MyView(View):
                # @method_decorator(csrf_exempt)  # 第一種可以不校驗的方式
                def dispatch(self, request, *args, **kwargs):
                    res = super().dispatch(request, *args, **kwargs)
                    return res

                def get(self,request):
                    return HttpResponse('get')

                def post(self,request):
                    return HttpResponse('post')

        總結 裝飾器中只有csrf_exempt是特例,其他的裝飾器在給CBV裝飾的時候 都可以有三種方式

        課後作業:
            將昨天的寫的登陸認證裝飾器 載入CBV上

        auth模組
            如果你想用auth模組   那麼你就用全套



            跟使用者相關的功能模組
                使用者的註冊 登陸 驗證 修改密碼 ...

            執行資料庫遷移命令之後  會生成很多表  其中的auth_user是一張使用者相關的表格
            新增資料
                createsuperuser  建立超級使用者 這個超級使用者就可以擁有登陸django admin後臺管理的許可權


        auth模組的功能
            查詢使用者
                from django.contrib import auth
                user_obj = auth.authenticate(username=username,password=password)  # 必須要用 因為資料庫中的密碼欄位是密文的 而你獲取的使用者輸入的是明文
            記錄使用者狀態
                auth.login(request,user_obj)  # 將使用者狀態記錄到session中
            判斷使用者是否登入
                print(request.user.is_authenticated)  # 判斷使用者是否登入  如果是你們使用者會返回False
            使用者登入之後 獲取使用者物件
                print(request.user)  # 如果沒有執行auth.login那麼拿到的是匿名使用者
            校驗使用者是否登入
                from django.contrib.auth.decorators import  login_required
                @login_required(login_url='/xxx/')  # 區域性配置
                def index(request):
                    pass

                # 全域性配置  settings檔案中
                LOGIN_URL = '/xxx/'
            驗證密碼是否正確
                request.user.check_password(old_password)
            修改密碼
                request.user.set_password(new_password)
                request.user.save()  # 修改密碼的時候 一定要save儲存 否則無法生效
            退出登陸
                auth.logout(request)  # request.session.flush()
            註冊使用者
                    # User.objects.create(username =username,password=password)  # 建立使用者名稱的時候 千萬不要再使用create 了
                    # User.objects.create_user(username =username,password=password)  # 建立普通使用者
                    User.objects.create_superuser(username =username,password=password,email='[email protected]')  # 建立超級使用者  郵箱必填


        自定義auth_user表
            from django.contrib.auth.models import AbstractUser
            # Create your models here.
            # 第一種 使用一對一關係  不考慮



            # 第二種方式   使用類的繼承
            class Userinfo(AbstractUser):
                # 千萬不要跟原來表中的欄位重複 只能創新
                phone = models.BigIntegerField()
                avatar = models.CharField(max_length=32)

            # 一定要在配置檔案中 告訴django
            # 告訴django  orm不再使用auth預設的表  而是使用你自定義的表
            AUTH_USER_MODEL = 'app01.Userinfo'  # '應用名.類名'


        1.執行資料庫遷移命令
            所有的auth模組功能 全部都基於你建立的表
            而不再使用auth_user



        settings功能插拔式原始碼
            參考django 配置檔案中的 中介軟體等功能模組
總結

 

 

django中介軟體規律一.png

 


django中介軟體規律二.png

 


django中介軟體重點 基於此做校驗.png

 


django後端全部邏輯.png

 


django後端全部邏輯更完整版 複習輔助.png

 

 

day59
diaoyuwangzhan
importidea