作者:小土豆biubiubiu
部落格園:https://www.cnblogs.com/HouJiao/
掘金:https://juejin.im/user/2436173500265335
微信公眾號:土豆媽的碎碎念(掃碼關注,一起吸貓,一起聽故事,一起學習前端技術)
作者文章的內容均來源於自己的實踐,如果覺得有幫助到你的話,可以點贊❤️給個鼓勵或留下寶貴意見
前言
最近需要做一個登入認證
的功能,所以想將整個的過程做一個記錄,方便以後回頭檢視,同時希望給我遇到同樣問題的同學一些參考。
因為認證是後端的功能,所以我這個不專業的前端在實現這個功能的時候不會深究太多。所以在記錄的過程中沒有過多的原理,著重記錄實現過程和這個過程中遇到的問題以及解決方案。
如果對登入這塊前後端流程原理不太懂的,可以先做一點功課,或者直接看我的整個操作和結果,看完之後會從結果和現象出發,在去理解學習登入認證原理就會更容易。
初始的環境介紹
前端框架
框架: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過期時間
關於
作者
小土豆biubiubiu
一個努力學習的前端小菜鳥,知識是無限的。堅信只要不停下學習的腳步,總能到達自己期望的地方
同時還是一個喜歡小貓咪的人,家裡有一隻美短小母貓,名叫土豆
部落格園
https://www.cnblogs.com/HouJiao/
掘金
https://juejin.im/user/2436173500265335
微信公眾號
土豆媽的碎碎念
微信公眾號的初衷是記錄自己和身邊的一些故事,同時會不定期更新一些技術文章
歡迎大家掃碼關注,一起吸貓,一起聽故事,一起學習前端技術
作者寄語
小小總結,歡迎大家指導~
參考文章
? django-rest-framework官方文件#許可權篇
? django-rest-framework官方文件#授權認證篇