Django之中間件和Auth模塊

CBV裝飾器css

寫一個裝飾器在session上html

def login_auth(func):
  def inner(request,*args,**kwargs):
    if request.session.get('is_login'):
      return func(request,*args,**kwargs)
       else:
      return redirect('/login/')
    return inner

三種方法:jquery

第一種就是直接在裏面給方法加上裝飾器,方法上面加,不要用原生的裝飾器,用的話,只能改參數,那樣的話不通用ajax

第二種就是在類的上面加裝飾器,name=‘方法’指向該方法數據庫

from django.utils.decoration import method_decorator
#
@method_decorator(login_auth,name='get') # 第二種 name參數必須指定 class MyHome(View):
  # @method_decorator(login_auth) # 第一種 def get(self,request): return HttpResponse('get') def post(self,request): return HttpResponse('post')

第三種:利用dispatch來裝飾全部的方法django

    class MyHome(View):
        @method_decorator(login_auth)  # 第三種  get和post都會被裝飾
        def dispatch(self, request, *args, **kwargs):
            super().dispatch(request,*args,**kwargs)
        def get(self,request):
            return HttpResponse('get')

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

 

中間件bootstrap

那麼,咱們仍是先來看一下Django的請求生命週期後端

 

 

從上面的圖中咱們能夠發現,中間件在這其中起到了很重要的做用。瀏覽器

它是一個輕量、低級別的插件系統,用於在全局範圍內改變Django的輸入和輸出。每一箇中間件組件都負責作一些特定的功能。session

在settings文件裏面就有這樣的中間件配置

 


django默認有七個中間件,可是django暴露給用戶能夠自定義中間件而且裏面能夠寫五種方法
ps:

1.請求來的時候會依次執行每個中間件裏面的process_request方法(若是沒有直接經過)
2.響應走的時候會依次執行每個中間件裏面的process_response方法(若是沒有直接經過)

django中間件可以幫我實現 網站全局的身份驗證,黑名單,白名單,訪問頻率限制,反爬相關
》》》:django用來幫你全局相關的功能校驗

自定義中間件
新建一個任意名字的文件夾,裏面新建一個任意名字py文件

from django.utils.deprecation import MiddlewareMixin

插件類:

process_request:請求來的時候從上往下依次執行每個中間件裏面的process_request


process_response :響應走的時候會從下往上依次執行每個中間件裏面的process_response方法


process_view:路由匹配成功執行視圖以前自動觸發(從上往下依次執行)


process_exception:當視圖函數報錯了,自動觸發(從下往上依次執行)


process_template_response:視圖函數返回的對象有一個render()方法

(或者代表該對象是一個TemplateResponse對象或等價方法)(從下往上依次執行)

 

自定義中間件

from django.utils.deprecation import MiddlewareMixin


class MyMiddleWare(MiddlewareMixin):
    def process_request(self, request):
        print('我是第一個自定義的中間件的process_request!')
# 寫一個路由與視圖,啓動項目,查看打印結果。
# 再寫一個自定義中間件

class MyMiddleWare(MiddlewareMixin):
    def process_request(self, request):
        print('我是第二個自定義的中間件的process_request!')
# 詮釋中間件的執行順序


# 在兩個中間件中添加process_response方法。研究中間件消息進出的順序
class MyMiddleWare(MiddlewareMixin):
    def process_request(self, request):
        print('我是第一個自定義的中間件的process_request!')
    def process_response(self,request,response):
          print('我是第一個自定義的中間件的process_response')
        return response
# 再來研究process_request中直接返回HttpReponse對象,會怎麼走接下來的process_response

# process_view,process_exception,process_template_response

 

csrf(跨站請求僞造)

先寫一個簡單的post請求,復現報錯信息

釣魚網站:銀行轉帳的路徑,你是否也能夠拿到,而後你作一個跟銀行如出一轍的頁面,也超銀行的藉口提交數據,當用戶在釣魚網站輸入對方帳戶名和轉帳金額以後,點擊發送。其實內部是將對方帳戶換成了釣魚網站的造假人員的帳戶。形成你轉帳轉錯帳戶的狀況

開兩個django項目,模擬轉帳的現象

如何區分釣魚網站和正經網站?在正經網站返回頁面的時候,在form表單中偷偷塞一個特殊的字符串,後端記下該頁面對應的字符串的值,等用戶發post請求來的時候,我先去校驗特殊的字符串是否匹配

如何去寫這個特殊的字符串呢?模版語法有一個固定的寫法{% csrf_token %},必須寫在form表單內

瀏覽器查看改標籤的值,而且每次都在刷新。再來演示剛剛轉帳的示例

ajax中如何設置csrf_token

 

# 只想給某個視圖韓式加上csrf校驗
from django.views.decorators.csrf import csrf_exempt,csrf_protect

# 局部禁用
@csrf_exempt
def index(request):
  pass

# 局部使用
@csrf_protect
def login(request):
  pass

 

轉帳釣魚案例

def transfer(request):
    if request.method == 'POST':
        username = request.POST.get("username")
        money = request.POST.get('money')
        others = request.POST.get('others')
        print('%s 給 %s 轉了 %s'%(username,others,money))
    return render(request,'transfer.html')
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.min.js"></script>
    <link rel="stylesheet" href="/static/bootstrap-3.3.7/css/bootstrap.min.css">
    <script src="/static/bootstrap-3.3.7/js/bootstrap.min.js"></script>
</head>
<body>
<h1>正經的網站</h1>
<form action="/index3/" method="post">
{#    {% csrf_token %}#}
    <p>username:<input type="text" name="username"></p>
    <p>money:<input type="text" name="money"></p>
    <p>others:<input type="text" name="others"></p>
    <input type="submit">
</form>
<button>ajax</button>
<script>
    $('button').click(function () {
        $.ajax({
            url:'',
            type:'post',
            data:{'name':'khan','csrfmiddlewaretoken':$('[name="csrfmiddlewaretoken"]').val()},
            success:function (data) {
                console.log(data)
            }
        })
    })

</script>

</body>
</html>

另起一個項目,釣魚頁面與原始頁面相似

經過像原網站發送請求,釣魚網站的一個input框就用戶替換了,這時候錢天然就流向了非法分子,有了{% csrf_token %},那麼服務端就不在接受釣魚網站的post請求

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.min.js"></script>
    <link rel="stylesheet" href="/static/bootstrap-3.3.7/css/bootstrap.min.css">
    <script src="/static/bootstrap-3.3.7/js/bootstrap.min.js"></script>
</head>
<body>
<h1>釣魚網站</h1>
<form action="http://127.0.0.1:8000/transfer/" method="post">
    <p>username:<input type="text" name="username"></p>
    <p>money:<input type="text" name="money"></p>
    <p>others:<input type="text"></p>
    <input type="text" name="others" value="khan" style="display:none">
    <input type="submit">
</form>
</body>
</html>

 

Auth認證模塊

 執行數據庫遷移的那兩條命令時,即便咱們沒有建表,也會出現autho_user表,咱們一塊兒來看一下怎麼操做該表。

from django.contrib import auth
from django.contrib.auth.models import User
def auth_login(request):
    if request.method == 'POST':
        username = request.POST.get('username')
        password = request.POST.get('password')
        # models.User.objects.filter(username=username,password=password).first()
        user_obj = auth.authenticate(request,username=username,password=password)
        if user_obj:
            # 記錄用戶狀態
            # request.session['name'] = 'khan'
            auth.login(request,user_obj)  # 一旦記錄了,能夠在任意的地方經過request.user獲取到當前登陸對象
            return HttpResponse('ok')

    return render(request,'auth_login.html')


def auth_index(request):
    print(request.user.is_authenticated())  # 判斷當前用戶是否已經登陸
    print(request.user,type(request.user))  # 獲取當前登陸用戶對象
    return HttpResponse('ok')


def auth_logout(request):
    auth.logout(request)  # request.session.flush()
    return HttpResponse('ok')


def auth_register(request):
    if request.method == 'POST':
        username = request.POST.get('username')
        password = request.POST.get('password')
        user_obj = auth.authenticate(request,username=username)
        if user_obj:
            return HttpResponse('當前用戶已存在')
        # models.User.objects.create(username=username,password=password)
        # 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='123@163.com')  # 建立超級用戶
    return render(request,'auth_register.html')

def auth_password(request):
    print(request.user.password)
    is_res = request.user.check_password('khan123')  # 校驗密碼是否一致
    if is_res:
        request.user.set_password('666')  # 設置新密碼
        request.user.save()  # 修改密碼必須save保存  否則無效
    return HttpResponse('ok')

裝飾器校驗是否登錄及跳轉

from django.contrib.auth.decorators import login_required

@login_required(login_url='/login/',redirect_field_name='old') 
# 沒登錄會跳轉到login頁面,而且後面會拼接上你上一次想訪問的頁面路徑/login/?next=/test/,能夠經過參數修改next鍵名 def my_view(request): pass

若是我全部的視圖函數都須要裝飾並跳轉到login頁面,那麼我須要寫好多份。

其實能夠去settings裏面去配置

# 能夠在配置文件中指定auth校驗登錄不合法統一跳轉到某個路徑
LOGIN_URL = '/login/'  # 既能夠局部配置,也能夠全局配置

 

自定義模型表應用auth功能

第一種:能夠創建一對一關係的模型表

from django.contrib.auth.model import User

class UserDetail(models.Models):
  phone = models.CharField(max_length=11)
  user = models.OnoToOneField(to=User)

第二種:面向對象繼承

from django.contrib.auth.models import User,AbstractUser
class UserInfo(AbstractUser):
  phone = models.CharField(max_length=32)

# 須要在配置文件中,指定我再也不使用默認的auth_user表而是使用我本身建立的Userinfo表
AUTH_USER_MODEL = "app名.models裏面對應的模型表名"
相關文章
相關標籤/搜索