Vue結合Django-Rest-Frameword結合實現登入認證(一)

小土豆biubiubiu發表於2020-09-21

作者:小土豆biubiubiu

部落格園:https://www.cnblogs.com/HouJiao/

掘金:https://juejin.im/user/2436173500265335

微信公眾號:土豆媽的碎碎念(掃碼關注,一起吸貓,一起聽故事,一起學習前端技術)

作者文章的內容均來源於自己的實踐,如果覺得有幫助到你的話,可以點贊❤️給個鼓勵或留下寶貴意見

前言

最近需要做一個登入認證的功能,所以想將整個的過程做一個記錄,方便以後回頭檢視,同時希望給我遇到同樣問題的同學一些參考。

因為認證是後端的功能,所以我這個不專業的前端在實現這個功能的時候不會深究太多。所以在記錄的過程中沒有過多的原理,著重記錄實現過程和這個過程中遇到的問題以及解決方案。

如果對登入這塊前後端流程原理不太懂的,可以先做一點功課,或者直接看我的整個操作和結果,看完之後會從結果和現象出發,在去理解學習登入認證原理就會更容易。

初始的環境介紹

前端框架

框架:Vue
HTTP庫:axios

後端專案

後端框架:基於pythondjango框架
WEB API:rest-framework
伺服器: centos
資料庫:PostgreSQL
python版本:2.7.5
django版本:1.10.1

關於後端資料庫的一些說明

資料庫使用的是PostgreSQL,並且已經對資料庫表進行了同步,命令為:python manage.py migrate

資料庫進行同步以後,會生成10相關的資料表。

需要關注的就是auth_user表這個表,它是django框架生成的使用者表,後面就使用這個表儲存使用者的資訊。

我們檢視一下這個表結構。

表裡面暫時沒有什麼資料。

接著我們來建立一個使用者,用於後期的登入測試:python manage.py createsuperuser

使用者建立成功,此時在去查詢資料表,就有一條使用者資訊了。

接下來就是登入驗證的實現了。

後端Django專案配置

Django登入認證配置

首先我們需要在setting.py檔案的INSTALLED_APPS配置登入認證的APP

INSTALLED_APPS = [
    ...
    'rest_framework.authtoken'
]

設定全域性的認證方案

接著在setting.py中配置全域性身份認證方案。

# 設定全域性身份認證方案
REST_FRAMEWORK = {
    'DEFAULT_AUTHENTICATION_CLASSES': (
        'rest_framework.authentication.TokenAuthentication',  # token認證
    )
}

資料庫同步

上面的配置完成需要進行資料庫同步:python manage.py migrate

在此檢視資料庫:

發現會多出來一個名為authtoken_token的資料表,這個表就是和使用者認證相關的資料表。

簡單測試

我們已經配置好了全域性的認證方式,那按道理來說,現在任意訪問後端的某個API就會出現為HTTP 401未經授權這樣的錯誤,那我們來試一試。

那結果發現請求還是可以正常發出。
這塊在網上搜尋了很久,看到有網友說關於setting設定的全域性身份認證方案配置有問題,正確的配置是

# 設定全域性身份認證方案
REST_FRAMEWORK = {
    'DEFAULT_PERMISSION_CLASSES': (
        'rest_framework.permissions.IsAuthenticated',
    ),
    'DEFAULT_AUTHENTICATION_CLASSES': (
        'rest_framework.authentication.TokenAuthentication',  # token認證
    )
}

DEFAULT_PERMISSION_CLASSES是關於使用者的許可權配置,如果沒有配置該項的話就是允許使用者無限制訪問,不管我們的請求是被認證或未認證的。

這塊可以看 ?官方文件 的說明

那加上這個認證以後呢,在去請求前面的API


發現這次終於有反應了,伺服器端返回了401,就是使用者認證失敗。

經過一陣思考後的再次測試

那接著我想起前面新增的IsAuthenticated授權配置,所以將setting進行了修改。

# 設定全域性身份認證方案
REST_FRAMEWORK = {
    'DEFAULT_PERMISSION_CLASSES': (
        'rest_framework.permissions.IsAuthenticated',
    ),
    # 'DEFAULT_AUTHENTICATION_CLASSES': (
    #     'rest_framework.authentication.TokenAuthentication',  # token認證
    # )
}

即註釋了全域性的使用者認證,保留了許可權認證,測試一下這個全域性的授權配置會對請求產生什麼影響。

我們發現這條API返回了403,也就是訪問的許可權出現了問題。

那不管怎麼樣,在單獨配置TokenAuthentication的情況下確實無法生效,而且官方文件也明確說明:如果沒有配置DEFAULT_PERMISSION_CLASSES就是允許使用者無限制訪問,不管我們的請求是被認證或未認證的。

所以如果需要進行使用者認證,那必須的也配上許可權驗證,使用者認證才會生效。

這個僅僅是自己的一個嘗試

後端Django專案實現登入API

接著我們來實現後端的登入介面

建立一個新的app

django-admin startapp userAuth

在views.py中編寫登入邏輯

# -*- coding: utf-8 -*-
# Create your views here.

from django.contrib import auth

from rest_framework.permissions import AllowAny
from rest_framework.authtoken.models import Token
from rest_framework.response import Response
from rest_framework.decorators import api_view, authentication_classes, permission_classes

@api_view(['POST'])
@permission_classes((AllowAny,))
@authentication_classes(())
def login(request):
    """登入"""
    result = True
    errorInfo = u''
    detail = {}
    data = request.data
    username = data.get('username')
    password = data.get('password')
    
    # 呼叫django進行使用者認證 
    # 驗證成功 user返回<class 'django.contrib.auth.models.User'>
    # 驗證失敗 user返回None
    user = auth.authenticate(username=username, password=password)
    print "user",user
    if user == None:
        result = False
        errorInfo = u'使用者名稱或密碼錯誤'
        return Response({"result": result, "detail": detail, "errorInfo": errorInfo})
    
    # 使用者名稱和密碼驗證成功
    # 獲取使用者的token 如果沒有token ,表示時使用者首次登入,則進行建立,並且返回token
    try:
        tokenObj = Token.objects.get(user_id=user.id)
    except Exception as e:
        # token 不存在 說明是首次登入
        tokenObj = Token.objects.create(user=user, token=token)
    # 獲取token字串
    token = tokenObj.key
    return Response({"result": result, "detail": {'token': token}, "errorInfo": errorInfo})

那登入的簡單程式碼邏輯就寫好了。

在這之前呢,我們先看下前面生成的關於使用者認證的資料表authtoken_token

暫時是沒有任何記錄,然後在產品的登入介面輸入使用者名稱和密碼。

這裡的使用者名稱和密碼就是前面使用python manage.py createsuperuser命令建立的admin賬戶

因為是首次登入,因此為該使用者建立token,即authtoken_token會產生一條記錄。

這裡給大家看一看我登入成功以後的authtoken_token資料表。

前端關於登入的邏輯處理

最後就是關於前端vue處的邏輯,我們先看一下登入頁面的methods邏輯。

login: function(){
      axios.post(url, this.loginForm).then(response =>{
          const {result, detail, errorInfo}  = response.data;
          if(result == true){
              // 登入成功
              // 設定token
              localStorage.setItem('token', detail.token);
              // 跳轉頁面
              this.$router.push('/certMake');
          }else{
              this.$message({
                  showClose: true,
                  message: errorInfo,
                  type: 'error'
              });
          }
      });
  }

可以看到登入成功以後我使用localStoragetoken進行本地儲存。

接著我們需要在訪問其他API時將這個token設定到請求頭部。

在這之前呢,我們先看一下API沒有新增token時的結果。

然後將token的資訊新增到請求頭。

// 別的模組的請求
getCertList: function(){
      const url = '/api/cert/certManage/certList';
      // 從localStorage獲取到登入時保持的token
      const auth = 'Token ' + localStorage.getItem('token');
      const header = {'Authorization':auth}
      axios.get(url, {'headers': header}).then(response =>{
          console.log(response.data);
          const {result, detail, errorInfo}  = response.data;
          if(result == true){
             this.certList = detail.certList;
          }else{
              this.$message({
                  showClose: true,
                  message: errorInfo,
                  type: 'error'
              });
          }
      });
}

然後在重新請求上面的API。

可以看到請求頭部已經新增上了token,而且響應的狀態碼也是200

那說明我們的登入頁面已經成功啦。

結語

那本篇文章是不是非常簡單呢(實際的我在嘗試的過程中差點頭禿?),但是還是有些功能是需要優化改進的。

那下一篇文章的內容會梳理以下幾點:

1. 優化axios:請求封裝、認證資訊設定的封裝 
2. 登出  
3. 設定token過期時間  

關於

作者

小土豆biubiubiu

一個努力學習的前端小菜鳥,知識是無限的。堅信只要不停下學習的腳步,總能到達自己期望的地方

同時還是一個喜歡小貓咪的人,家裡有一隻美短小母貓,名叫土豆

部落格園

https://www.cnblogs.com/HouJiao/

掘金

https://juejin.im/user/2436173500265335

微信公眾號

土豆媽的碎碎念

微信公眾號的初衷是記錄自己和身邊的一些故事,同時會不定期更新一些技術文章

歡迎大家掃碼關注,一起吸貓,一起聽故事,一起學習前端技術

作者寄語

小小總結,歡迎大家指導~

參考文章

? django-rest-framework官方文件#許可權篇
? django-rest-framework官方文件#授權認證篇

相關文章