本文基于之前的一個旅游網站,實現 Django 連接 vue3,使 vue3 能攜帶 CSRF Token 發送 axios 請求給后端,后端再響應數據給前端。想要源碼直接滑倒底部。
目錄
實現效果
解決跨域
獲取 csrf-token
什么是??csrf-token??
CSRF攻擊的工作原理
CSRF Token的作用
在前后端分離項目中的應用
問題
解決方案
Django 獲取 CSRF Token
前端獲取
?配置 Vite 代理
下載 axios
請求?CSRF Token
運行前后端項目
請求與相應
請求
響應
后端返回數據
前端接收數據
源碼獲取
實現效果
Django5連接前端vue3,前后端分離式項目(Django+vue3+csrf-token+axios)
解決跨域
下載解決跨域的包:
pip install django-cors-headers
注冊,并配置中間件
INSTALLED_APPS = ["corsheaders",
]
MIDDLEWARE.insert(0, 'corsheaders.middleware.CorsMiddleware')
允許其他端口來源(僅用于開發環境)
CORS_ALLOW_ALL_ORIGINS = True
獲取 csrf-token
什么是??csrf-token??
????????Django中的CSRF Token(Cross-Site Request Forgery Token,跨站請求偽造令牌)主要用于防止CSRF攻擊。這是一種針對網站的惡意攻擊模式,攻擊者通過偽裝來自受信任用戶的請求來利用已認證的用戶數據進行非法操作。
CSRF攻擊的工作原理
????????假設你登錄了一個銀行網站,并且在沒有登出的情況下訪問了一個惡意網站。如果該銀行網站對某些敏感操作(如轉賬)的安全措施不足,惡意網站可以通過自動提交表單或發送AJAX請求的方式,利用你的身份和已登錄狀態向銀行網站發起轉賬請求。由于請求是從你的瀏覽器發出的,同時包含有效的會話Cookie,銀行服務器無法區分這個請求是合法的還是偽造的,從而可能導致資金被非法轉移。
CSRF Token的作用
為了防止上述情況發生,Django使用CSRF Token作為額外的安全層。具體工作流程如下:
-
生成Token:當用戶訪問一個包含表單的頁面時,Django會在響應中設置一個名為
csrftoken
的Cookie,并且在HTML表單中插入一個隱藏字段,其值為相同的CSRF Token。 -
驗證Token:當用戶提交表單時,無論是通過POST請求還是其他非安全方法(如PUT、DELETE等),Django都會檢查請求中的CSRF Token是否與存儲在Cookie中的Token相匹配。只有當兩者匹配時,才會處理該請求;否則,請求將被拒絕并返回403 Forbidden錯誤。
-
安全性保障:這種方法有效地阻止了第三方網站直接構造請求并利用已登錄用戶的會話信息執行未授權操作的可能性,因為它們無法獲取到正確的CSRF Token。
在前后端分離項目中的應用
????????在傳統的Django項目中,模板渲染機制使得CSRF Token很容易集成進每個需要保護的表單或AJAX請求中。然而,在前后端分離的應用場景下,前端可能是一個獨立運行的Vue.js、React或其他JavaScript框架開發的應用,這種情況下,獲取和使用CSRF Token需要一些額外的工作,比如通過特定的API接口獲取Token,并確保每次請求都正確地包含了這個Token。這通常涉及到在前端代碼中添加邏輯來獲取和附加CSRF Token到請求頭中。
問題
Django 默認啟用了 CSRF 保護機制,要求所有非安全 HTTP 方法(如 POST、PUT、DELETE)必須包含有效的 CSRF Token。如果前端未正確獲取或發送 CSRF Token,就會觸發以下錯誤:
CSRF verification failed. Request aborted.
CSRF cookie not set.
在傳統的 Django 項目中,CSRF Token 通常是通過模板渲染(如 {% csrf_token %}
)或默認機制生成的,并存儲在 Cookie 中,其中,{% csrf_token %}在我之前的所有 Django 教程中都在html頁面中編寫了
。然而,在前后端分離的架構中:
- 前端和后端是獨立運行的。
- 前端可能不會直接加載 Django 提供的頁面,因此無法自動獲取 CSRF Token。
?
解決方案
Django 獲取 CSRF Token
Django 提供了一個專門的視圖??/csrf/?
,可以用來手動獲取 CSRF Token。你可以通過以下步驟實現:
配置 Django 視圖
在 Django 的 urls.py
文件中添加一個視圖來返回 CSRF Token:
from django.middleware.csrf import get_token
from django.http import JsonResponsedef get_csrf_token(request):token = get_token(request)return JsonResponse({'csrfToken': token})
然后在 urlpatterns
中注冊該視圖:
from django.urls import path
from . import viewsurlpatterns = [...path('csrf/', views.get_csrf_token, name='get_csrf_token'),
]
前端獲取
?配置 Vite 代理
import { defineConfig } from 'vite';
import vue from '@vitejs/plugin-vue';
import path from 'path';export default defineConfig({server: {proxy: {'/api': {target: 'http://127.0.0.1:8080', // 確保與 Django 后端地址一致changeOrigin: true,rewrite: (path) => path.replace(/^\/api/, ''),secure: false, // 如果后端使用 HTTPS,可能需要設置為 true},},},resolve: {alias: {'@': path.resolve(__dirname, 'src'),},},plugins: [vue()],
});
下載 axios
npm install axios
請求?CSRF Token
import axios from 'axios';let csrfToken = null;// 獲取 CSRF Token
async function fetchCsrfToken() {try {const response = await axios.get('/api/csrf/');csrfToken = response.data.csrfToken;console.log("CSRF Token:", csrfToken);} catch (error) {console.error("Error fetching CSRF token:", error.response?.data || error.message);}
}fetchCsrfToken()
運行前后端項目
# 運行后端
python manage.py runserver 8080// 運行前端
npm run dev
后端處理請求:
前端獲取到?token:
有了 token 之后,前端的一系列數據就能被后端安全接收,像用戶管理之類的功能就能安全得進行了。
請求與相應
前端如何發送請求給 Django,Django 又如何相應數據給前端?
請求
前面講的 前端獲取 csrf-token 其實就是響應。配置 Vite 代理后,再使用 axios 發送請求給?Django:
這里我再給個示例:
前端通過 /api/ask 發送請求,攜帶 CSRF Token 請求頭,將用戶輸入的 question 以 json 形式發POST 給 Django :
async function sendQuestion() {if (!csrfToken) {console.error("CSRF Token is not available");return;}try {const response = await axios.post('/api/ask/', { question: question.value }, {headers: {'X-CSRFToken': csrfToken, // 添加 CSRF Token 到請求頭'Content-Type': 'application/json', // 指定內容類型為 JSON},});console.log("Response from Django:", response.data);} catch (error) {console.error("Error sending question:", error.response?.data || error.message);}
}
后端定義 url:
path('ask/', views.ai_talk, name='ai_talk'), # 使用類視圖
視圖函數接收前端的 POST 數據并解析:
def ai_talk(request):if request.method == 'POST':try:# 從請求體中獲取 JSON 數據body = request.body.decode('utf-8') # 將字節流解碼為字符串data = json.loads(body) # 將 JSON 字符串解析為 Python 字典# 獲取用戶輸入的問題user_question = data.get('question', '').strip()print(f"用戶輸入的問題: {user_question}")except Exception as e:# 處理異常print(f"解析請求數據失敗: {e}")return HttpResponse("請求數據無效", status=400)else:# 如果不是 POST 請求,返回錯誤return HttpResponse("僅支持 POST 請求", status=405)
得到數據:
響應
后端返回數據
Django 已經接收到了數據,可以通過 HttpResponse 或??JsonResponse 將數據返回,這里使用JsonResponse 以 json格式返回數據,僅需在視圖函數中加入返回代碼:
# 返回 JSON 響應
return JsonResponse({'status': 'success','message': ai_response,
})
前端接收數據
定義一個列表接收返回數據
const aiResponse = ref<string[]>([]); // 響應數據列表
在前端發送問題的同時,請求后端的響應:
// 發送問題到后端
async function sendQuestion() {if (!csrfToken) {console.error("CSRF Token is not available");return;}try {const response = await axios.post('/api/ask/', { question: question.value }, {headers: {'X-CSRFToken': csrfToken, // 添加 CSRF Token 到請求頭'Content-Type': 'application/json', // 指定內容類型為 JSON},});// 獲取后端返回的數據const responseData = response.data;console.log("Response from Django:", responseData);if (responseData.status === 'success') {//添加數據到相應列表aiResponse.value.push(responseData.message);} else {console.error("Error from backend:", responseData.message);}// 清空問題輸入框question.value = '';} catch (error) {console.error("Error sending question:", error.response?.data || error.message);}
}
再顯示到頁面上。
源碼獲取
上面是?Django?代碼,下面是?vue3?代碼。
資源地址:https://download.csdn.net/download/2403_83182682/90578132
感謝您的觀看!!!