Wii
Wii
发布于 2025-09-29 / 5 阅读
0
0

Django 的 CSRF 问题

TL;DR

CSRF 的一个 case,原因是前端接口访问的是 api/v1/tools/wakeonlan/trigger/ ,Django URL 中设置的 path 是 api/v1/tools/wakeonlan/trigger 不匹配导致的,在 Django urls.py 中的 path 追加 / 解决。

问题描述

在开发岚枢时,新增了一个 Wake On Lan 的接口,但是报 CSRF 的错。

Reason given for failure:

    Origin checking failed - http://192.168.6.5:9808 does not match any trusted origins.

很奇怪,django-rest-framework 框架的请求就没这个问题。

Vite 的 Proxy 配置

// https://vite.dev/config/
export default defineConfig({
  plugins: [react(), tailwindcss()],
  server: {
    host: "0.0.0.0",
    port: 9808,
    proxy: {
      "/api": {
        target: "http://127.0.0.1:8620",
        changeOrigin: true,
      },
    },
  },
  resolve: {
    alias: {
      "@": path.resolve(__dirname, "./src"),
    },
  },
  css: {
    preprocessorOptions: {
      less: {
        javascriptEnabled: true,
      },
    },
  },
});

Trae CN 的解决方案

from rest_framework.views import APIView
from django.views.decorators.csrf import csrf_exempt
...

@csrf_exempt
class WakeOnLanAPIView(APIView):
    """
    Wake-on-LAN API视图
    接收MAC地址并发送唤醒包
    """

首先,是多引入了一次 APIView;其次,对类使用 csrf_exempt 修饰,在 urls 中使用 as_view 方法时会报错,原因是已经把类修饰为方法了。

提示还是会重复引入,还给出了其他的答案。

from django.utils.decorators import method_decorator

@method_decorator(csrf_exempt, name="dispatch")
class WakeOnLanAPIView(APIView):

另外一个答案。

from django.views.decorators.csrf import csrf_exempt

urlpatterns += [
    path("tools/wakeonlan/trigger/", csrf_exempt(WakeOnLanAPIView.as_view()), name="wake_on_lan_api"),
]

最后都没有解决。

Cursor

Cursor 给出的答案。

diff --git a/api/urls.py b/api/urls.py
index 9e4817d..b342e0f 100644
--- a/api/urls.py
+++ b/api/urls.py
@@ -26,5 +26,5 @@ urlpatterns = [
 
 # 工具类 API
 urlpatterns += [
-    path("tools/wakeonlan/trigger", WakeOnLanAPIView.as_view(), name="wake_on_lan_api"),
+    path("tools/wakeonlan/trigger/", WakeOnLanAPIView.as_view(), name="wake_on_lan_api"),
 ]
diff --git a/misthub/settings.py b/misthub/settings.py
index 759251f..41b346e 100644
--- a/misthub/settings.py
+++ b/misthub/settings.py
@@ -34,6 +34,13 @@ DEBUG = True
 
 ALLOWED_HOSTS = ["*"]
 
+# Allow cross-origin POSTs from dev frontend origins to satisfy CSRF origin check
+CSRF_TRUSTED_ORIGINS = [
+    "http://192.168.6.5:9808",
+    "http://localhost:9808",
+    "http://127.0.0.1:9808",
+]

其实只改 urls.py 文件,在 path 后面新增 / 就可以解决了。

使用 Cursor 相同提示词

回滚改动,使用和 Cursor 相同提示词,再次询问 Trae CN。

index 759251f..b595d0a 100644
--- a/misthub/settings.py
+++ b/misthub/settings.py
@@ -142,3 +142,8 @@ MEDIA_ROOT = os.path.join(BASE_DIR, "media")
 # https://docs.djangoproject.com/en/5.2/ref/settings/#default-auto-field
 
 DEFAULT_AUTO_FIELD = "django.db.models.BigAutoField"
+
+# 跨域请求配置
+CSRF_TRUSTED_ORIGINS = [
+    "http://192.168.6.5:9808",
+]
diff --git a/pyproject.toml b/pyproject.toml
index e12bad9..ef9e6a1 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -10,6 +10,7 @@ dependencies = [
   "mysqlclient (>=2.2.7,<3.0.0)",
   "djangorestframework (>=3.16.1,<4.0.0)",
   "cryptography (>=45.0.7,<46.0.0)",
+  "django-cors-headers (>=4.4.0,<5.0.0)",
 ]

没有发现问题,继续提示。

还是继续改 settings.py,放弃。

原因

前端接口访问的是 api/v1/tools/wakeonlan/trigger/ ,Django URL 中设置的 path 如下。

urlpatterns += [
    path("tools/wakeonlan/trigger", WakeOnLanAPIView.as_view(), name="wake_on_lan_api"),
]

在 path 后增加 / 就好了。


评论