1. 程式人生 > 其它 >Django的中介軟體和auth模組

Django的中介軟體和auth模組

Django中介軟體

"""
django中介軟體是django的門戶
1.請求來的時候需要先經過中介軟體才能到達真正的django後端
2.響應走的時候最後也需要經過中介軟體才能傳送出去

django自帶七個中介軟體
"""

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', ] 首先需要繼承MiddlewareMixin from django.utils.deprecation import MiddlewareMixin django自定義中介軟體五個可以自定義的方法 1.必須掌握 process_request
#請求進來 process_response #響應請求(返回給頁面) 2.瞭解即可 process_view process_template_response process_exception

 

如何自定義中介軟體

"""
1.在專案名或者應用名下建立一個任意名稱的資料夾
2.在該資料夾內建立一個任意名稱的py檔案
3.在該py檔案內需要書寫類(這個類必須繼承MiddlewareMixin)
    然後在這個類裡面就可以自定義五個方法了
    (這五個方法並不是全部都需要書寫,用幾個寫幾個)
4.需要將類的路徑以字串的形式註冊到配置檔案中才能生效
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',
    '你自己寫的中介軟體的路徑1',
    '你自己寫的中介軟體的路徑2',
    '你自己寫的中介軟體的路徑3',
]

""" """ 1.必須掌握 process_request 1.請求來的時候需要經過每一箇中間件裡面的process_request方法 結果的順序是按照配置檔案中註冊的中介軟體從上往下的順序依次執行 2.如果中介軟體裡面沒有定義該方法,那麼直接跳過執行下一個中介軟體 3.如果該方法返回了HttpResponse物件,那麼請求將不再繼續往後執行 而是直接原路返回(校驗失敗不允許訪問...) process_request方法就是用來做全域性相關的所有限制功能 process_response 1.響應走的時候需要結果每一箇中間件裡面的process_response方法 該方法有兩個額外的引數request,response 2.該方法必須返回一個HttpResponse物件 1.預設返回的就是形參response 2.你也可以自己返回自己的 3.順序是按照配置檔案中註冊了的中介軟體從下往上依次經過 如果你沒有定義的話 直接跳過執行下一個 研究如果在第一個process_request方法就已經返回了HttpResponse物件,那麼響應走的時候是經過所有的中介軟體裡面的process_response還是有其他情況 是其他情況 就是會直接走同級別的process_reponse返回 flask框架也有一箇中間件但是它的規律 只要返回資料了就必須經過所有中介軟體裡面的類似於process_reponse方法 2.瞭解即可 process_view 路由匹配成功之後執行檢視函式之前,會自動執行中介軟體裡面的該放法 順序是按照配置檔案中註冊的中介軟體從上往下的順序依次執行 process_template_response 返回的HttpResponse物件有render屬性的時候才會觸發 順序是按照配置檔案中註冊了的中介軟體從下往上依次經過 process_exception 當檢視函式中出現異常的情況下觸發 順序是按照配置檔案中註冊了的中介軟體從下往上依次經過 """

 

csrf跨站請求偽造

"""
釣魚網站
    我搭建一個跟正規網站一模一樣的介面(中國銀行)
    使用者不小心進入到了我們的網站,使用者給某個人打錢
    打錢的操作確確實實是提交給了中國銀行的系統,使用者的錢也確確實實減少了
    但是唯一不同的時候打錢的賬戶不適用戶想要打的賬戶變成了一個莫名其妙的賬戶
內部本質
    我們在釣魚網站的頁面 針對對方賬戶 只給使用者提供一個沒有name屬性的普通input框
    然後我們在內部隱藏一個已經寫好name和value的input框

如何規避上述問題
    csrf跨站請求偽造校驗
        網站在給使用者返回一個具有提交資料功能頁面的時候會給這個頁面加一個唯一標識
        當這個頁面朝後端傳送post請求的時候 我的後端會先校驗唯一標識,如果唯一標識不對直接拒絕(403 forbbiden)如果成功則正常執行    
"""

 

  如何符合校驗

# form表單如何符合校驗
<form action="" method="post">
    {% csrf_token %}
    <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>

# ajax如何符合校驗
// 第一種 利用標籤查詢獲取頁面上的隨機字串
{#data:{"username":'jason','csrfmiddlewaretoken':$('[name=csrfmiddlewaretoken]').val()},#}
// 第二種 利用模版語法提供的快捷書寫
{#data:{"username":'jason','csrfmiddlewaretoken':'{{ csrf_token }}'},#}
// 第三種 通用方式直接拷貝js程式碼並應用到自己的html頁面上即可
    
{% load static %}
<script src="{% static 'js/mysetup.js' %}"></script>
data:{"username":'jason'}
//mysetup.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);
    }
  }
});
mysetup.js

 

  csrf相關裝飾器

"""
1.網站整體都不校驗csrf,就單單幾個檢視函式需要校驗
2.網站整體都校驗csrf,就單單幾個檢視函式不校驗
"""
from django.views.decorators.csrf import csrf_protect,csrf_exempt
from django.utils.decorators import method_decorator
"""
csrf_protect  需要校驗
    針對csrf_protect符合我們之前所學的裝飾器的三種玩法
csrf_exempt   忽視校驗
    針對csrf_exempt只能給dispatch方法加才有效
"""
# @csrf_exempt
# @csrf_protect
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')



from django.views import View

# @method_decorator(csrf_protect,name='post')  # 針對csrf_protect 第二種方式可以
# @method_decorator(csrf_exempt,name='post')  # 針對csrf_exempt 第二種方式不可以
@method_decorator(csrf_exempt,name='dispatch')
class MyCsrfToken(View):
    # @method_decorator(csrf_protect)  # 針對csrf_protect 第三種方式可以
    # @method_decorator(csrf_exempt)  # 針對csrf_exempt 第三種方式可以
    def dispatch(self, request, *args, **kwargs):
        return super(MyCsrfToken, self).dispatch(request,*args,**kwargs)

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

    # @method_decorator(csrf_protect)  # 針對csrf_protect 第一種方式可以
    # @method_decorator(csrf_exempt)  # 針對csrf_exempt 第一種方式不可以
    def post(self,request):
        return HttpResponse('post')

 

Auth模組

"""
其實我們在建立好一個django專案之後直接執行資料庫遷移命令會自動生成很多表
    django_session
    auth_user
django在啟動之後就可以直接訪問admin路由,需要輸入使用者名稱和密碼,資料參考的就是auth_user表,並且還必須是管理員使用者才能進入

建立超級使用者(管理員)
    python3 manage.py createsuperuser
    
依賴於auth_user表完成使用者相關的所有功能
"""

 

  方法總結

# 1.比對使用者名稱和密碼是否正確
user_obj = auth.authenticate(request,username=username,password=password)
# 括號內必須同時傳入使用者名稱和密碼
print(user_obj)  # 使用者物件  jason   資料不符合則返回None
print(user_obj.username)  # jason
print(user_obj.password)  # 密文

# 2.儲存使用者狀態
auth.login(request,user_obj)  # 類似於request.session[key] = user_obj
# 主要執行了該方法 你就可以在任何地方通過request.user獲取到當前登陸的使用者物件

# 3.判斷當前使用者是否登陸
request.user.is_authenticated()

# 4.獲取當前登陸使用者
request.user

# 5.校驗使用者是否登陸裝飾器
from django.contrib.auth.decorators import login_required
# 區域性配置
@login_required(login_url='/login/') 
# 全域性配置
LOGIN_URL = '/login/'
    1.如果區域性和全域性都有 該聽誰的?
    區域性 > 全域性
    2.區域性和全域性哪個好呢?
    全域性的好處在於無需重複寫程式碼 但是跳轉的頁面卻很單一
    區域性的好處在於不同的檢視函式在使用者沒有登陸的情況下可以跳轉到不同的頁面

# 6.比對原密碼
request.user.check_password(old_password)

# 7.修改密碼
request.user.set_password(new_password)  # 僅僅是在修改物件的屬性
request.user.save()  # 這一步才是真正的操作資料庫

# 8.登出
auth.logout(request) 

# 9.註冊
# 操作auth_user表寫入資料
User.objects.create(username=username,password=password)  # 寫入資料  不能用create 密碼沒有加密處理

# 建立普通使用者
User.objects.create_user(username=username,password=password)

# 建立超級使用者(瞭解):使用程式碼建立超級使用者 郵箱是必填的 而用命令建立則可以不填
User.objects.create_superuser(username=username,email='[email protected]',password=password)

 

  如何擴充套件auth_user表

from django.db import models
from django.contrib.auth.models import User,AbstractUser
# Create your models here.

# 第一種:一對一關係  不推薦
# class UserDetail(models.Model):
#     phone = models.BigIntegerField()
#     user = models.OneToOneField(to='User')


# 第二種:面向物件的繼承
class UserInfo(AbstractUser):
    """
    如果繼承了AbstractUser
    那麼在執行資料庫遷移命令的時候auth_user表就不會再創建出來了
    而UserInfo表中會出現auth_user所有的欄位外加自己擴充套件的欄位
    這麼做的好處在於你能夠直接點選你自己的表更加快速的完成操作及擴充套件
    
    前提:
        1.在繼承之前沒有執行過資料庫遷移命令
            auth_user沒有被建立,如果當前庫已經建立了那麼你就重新換一個庫
        2.繼承的類裡面不要覆蓋AbstractUser裡面的欄位名
            表裡面有的欄位都不要動,只擴充套件額外欄位即可
        3.需要在配置檔案中告訴django你要用UserInfo替代auth_user(******)
            AUTH_USER_MODEL = 'app01.UserInfo'
                                '應用名.表名'
    """
    phone = models.BigIntegerField()
    
    
"""
你如果自己寫表替代了auth_user那麼
auth模組的功能還是照常使用,參考的表頁由原來的auth_user變成了UserInfo

"""