1、配置JWT和跨域請求
vue和django的請求是跨域請求, 因此要配置跨域請求
在settings.py中新增如下程式碼
INSTALLED_APPS = [
"django.contrib.admin",
"django.contrib.auth",
"django.contrib.contenttypes",
"django.contrib.sessions",
"django.contrib.messages",
"django.contrib.staticfiles",
"app01.apps.App01Config",
'corsheaders', #允許跨域訪問之1--它是 Django REST framework 的一個擴充套件,它提供了一種簡單的方式來處理跨域資源共享(CORS)問題
'rest_framework',#JWT之1--引入rest_framework,rest_framework是Django框架中的一個擴充套件包,能夠幫助開發者簡化RESTful API的開發過程,提高開發效率。
'rest_framework_simplejwt',#JWT之2--是 Django REST framework 的一個擴充套件,它提供了 JWT 認證的功能
]
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",
'corsheaders.middleware.CorsMiddleware', #允許跨域訪問之2--它是 Django REST framework 的 corsheaders 擴充套件中的一箇中介軟體
]
#允許跨域訪問之3--域名白名單
CORS_ALLOWED_ORIGINS = [
"http://localhost:5173", # Vue應用的地址,注意要和自己的專案對應有的人埠是8080
]
#JWT之3--配置JWT的引數
SIMPLE_JWT = {
'ACCESS_TOKEN_LIFETIME': timedelta(minutes=60), # ACCESS_TOKEN的有效期為60分鐘
'REFRESH_TOKEN_LIFETIME': timedelta(days=15), # REFRESH_TOKEN的有效期為15天
'ROTATE_REFRESH_TOKENS': False, # 重新整理令牌輪換功能關閉
'BLACKLIST_AFTER_ROTATION': False, # 重新整理令牌輪換後不會將舊令牌列入黑名單
'UPDATE_LAST_LOGIN': False, # 不會更新使用者的最後登入時間
'ALGORITHM': 'HS256', # 使用HS256演算法進行簽名
'SIGNING_KEY': 'suijizifc', # 簽名金鑰
'VERIFYING_KEY': None, # 驗證金鑰
'AUDIENCE': None, # 受眾
'ISSUER': None, # 發行者
'JWK_URL': None, # JSON Web Key URL
'LEEWAY': 0, # 允許的時間偏差
'AUTH_HEADER_TYPES': ('Bearer',), # 授權頭型別
'AUTH_HEADER_NAME': 'HTTP_AUTHORIZATION', # 授權頭名稱
'USER_ID_FIELD': 'id', # 使用者ID欄位
'USER_ID_CLAIM': 'user_id', # 使用者ID宣告
'USER_AUTHENTICATION_RULE': 'rest_framework_simplejwt.authentication.default_user_authentication_rule', # 使用者認證規則
'AUTH_TOKEN_CLASSES': ('rest_framework_simplejwt.tokens.AccessToken',), # 授權令牌類
'TOKEN_TYPE_CLAIM': 'token_type', # 令牌型別宣告
'TOKEN_USER_CLASS': 'rest_framework_simplejwt.models.TokenUser', # 令牌使用者類
'JTI_CLAIM': 'jti', # JWT ID宣告
'SLIDING_TOKEN_REFRESH_EXP_CLAIM': 'refresh_exp', # 滑動令牌重新整理過期宣告
'SLIDING_TOKEN_LIFETIME': timedelta(minutes=5), # 滑動令牌的有效期為5分鐘
'SLIDING_TOKEN_REFRESH_LIFETIME': timedelta(days=1), # 滑動令牌的重新整理期為1天, # End of Selection
}
2、製作帶有JWT驗證功能的檢視
做JWT驗證的檢視函式,必須封裝在類內, 例如我將這個類寫在views/imgs_get.py檔案裡了
函式名稱是固定的, 開發者自定義名稱的函式不能被直接呼叫. 如果是get請求,函式名必須為get; 如果是post請求,函式名必須為post
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework.permissions import IsAuthenticated
from app01.models import Imgs
from django.http import JsonResponse
class ImgsGetView(APIView):
permission_classes = ([IsAuthenticated])#驗證access令牌
#這裡是get請求,所以函式名必須為get
def get(self, request):
imgs=Imgs.objects.all()
imgs_list=[]
for img in imgs:
imgs_list.append({'id':img.id,'img_num':img.img_num,'img_name':img.img_name,'img_time':img.img_time})
return JsonResponse({'result': 'success', 'message': imgs_list})
由於函式封裝在類內,而非普通函式, 所以對應的urls.py的配置也要改變
from app01.views.imgs_get import ImgsGetView#載入檢視類
urlpatterns = [
...
path('api/ImgsGet/',ImgsGetView.as_view(),name='ImgsGet'),
...
]
對應的Vue的請求方式也要傳送變化, 即要攜帶令牌資訊
axios.get('http://127.0.0.1:8000/api/ImgsGet/', {
headers: {
'Authorization': 'Bearer ' + 令牌資訊
}
})
3、令牌資訊如何獲取呢
在登陸時, 將使用者名稱和密碼傳給TokenObtainPairView, 這是應該django自帶的驗證使用者資訊並返回令牌的類, 我們只需要在urls.py裡給這個類指定一個訪問連結即可
path('api/token/', TokenObtainPairView.as_view(), name='token_obtain_pair')
登入並獲取令牌,Login.vue
<template>
<div class="login-container">
<h1>Login</h1>
<form @submit.prevent="handleSubmit">
<label for="username">Username:</label>
<input id="username" v-model="username" type="text" required>
<label for="password">Password:</label>
<input id="password" v-model="password" type="password" required>
<button type="submit">Login</button>
</form>
</div>
</template>
<script setup>
import axios from 'axios';
import { ref } from 'vue';
import router from '@/router';
let username=ref()
let password=ref()
async function handleSubmit() {
try {
//提交登入資訊給TokenObtainPairView
const res = await axios.post('http://127.0.0.1:8000/api/token/', {
username: username.value,
password: password.value
});
const { access, refresh } = res.data;
//將獲取的JWT存到localstorage裡持久化, localStorage相當於一個全域性字典, 以後再任何檔案裡想要存資料都可以使用它,支援跨檔案存取,即a檔案中存的,b檔案中可以讀
//儲存資料: localStorage.setItem('資料名', 資料值);
//讀取資料: localStorage.getItem('資料名');
localStorage.setItem('access', access);//access令牌
localStorage.setItem('refresh', refresh);//refresh令牌, 其他功能的令牌,本次用不到,暫不展開
localStorage.setItem('username', username.value);
router.push('/home/video');
} catch (error) {
console.log('登陸失敗的返回:', error);
alert('登陸失敗的返回:'+error);
}
}
</script>
<style scoped>
</style>
4、攜帶access令牌請求
axios.get('http://127.0.0.1:8000/api/ImgsGet/', {
headers: {
'Authorization': 'Bearer ' + localStorage.getItem('access')#攜帶access令牌資訊
}
})
在access令牌裡, 是包含了使用者資訊的, 比如使用者id, 在攜帶令牌請求時, django會自動解析請求中的JWT令牌,並將使用者資訊新增到request物件中。因此我們可以透過request.user來訪問這個使用者資訊, 比如
from rest_framework.views import APIView
from rest_framework.permissions import IsAuthenticated
from django.http import JsonResponse
from django.contrib.auth.models import User
# from icecream import ic
class BandEmailView(APIView):
permission_classes = ([IsAuthenticated])
#這裡是post請求,函式名必須為post
def post(self, request):
if request.method == 'POST':
email = request.POST.get('email')
#django會自動解析請求中的JWT令牌,並將使用者資訊新增到request物件中。因此我們可以透過request.user來訪問這個使用者資訊
user_id = request.user.id#獲取使用者id
print('user_id',user_id)
user = User.objects.filter(id=user_id).first()
user.email = email
user.save()
return JsonResponse({'result': 'success'})
return JsonResponse({'result': 'error'})
小技巧
如果覺得每次請求都要寫令牌資訊太麻煩,可以將請求封裝一下,如我在vue-project/public/js/myjs.js裡封裝了應該axios請求
const instance = axios.create({
baseURL: 'http://127.0.0.1:8000',
timeout: 1000,
headers: {
'Authorization': `Bearer ${localStorage.getItem('access')}`
}
})
以後請求時直接使用 instance
instance.get('http://127.0.0.1:8000/api/ImgsGet/')