作者:小土豆
博客園:https://www.cnblogs.com/HouJiao/
掘金:https://juejin.im/user/58c61b4361ff4b005d9e894d
微信公眾號:不知名寶藏程序媛(關注"不知名寶藏程序媛"免費領取前端電子書籍。文章公眾號首發,關注公眾號第一時間獲取最新文章。)
碼字不易,點贊鼓勵喲~
前言
最近需要做一個登錄認證的功能,所以想將整個的過程做一個記錄,方便以后回頭查看,同時希望給我遇到同樣問題的同學一些參考。
因為認證是后端的功能,所以我這個不專業的前端在實現這個功能的時候不會深究太多。所以在記錄的過程中沒有過多的原理,着重記錄實現過程和這個過程中遇到的問題以及解決方案。
如果對登錄這塊前后端流程原理不太懂的,可以先做一點功課,或者直接看我的整個操作和結果,看完之后會從結果和現象出發,在去理解學習登錄認證原理就會更容易。
初始的環境介紹
前端框架
框架:Vue
HTTP庫:axios
后端項目
后端框架:基於python的django框架
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'
});
}
});
}
可以看到登錄成功以后我使用localStorage將token進行本地存儲。
接着我們需要在訪問其他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過期時間
參考文章
👉 django-rest-framework官方文檔#權限篇
👉 django-rest-framework官方文檔#授權認證篇
作者:小土豆
博客園:https://www.cnblogs.com/HouJiao/
掘金:https://juejin.im/user/58c61b4361ff4b005d9e894d
微信公眾號:不知名寶藏程序媛(關注"不知名寶藏程序媛"免費領取前端電子書籍。文章公眾號首發,關注公眾號第一時間獲取最新文章。)
碼字不易,點贊鼓勵喲~
