【Django+微信小程序】前后端分离跨站点POST请求踩坑实录

问题描述

django版本3.2
在做前后端分离项目过程中需要用到跨站点POST请求,但会被django拦截。尽管将settings.py中的django.middleware.csrf.CsrfViewMiddleware注释掉可以解决,但在正式部署的情况下是不能这么做的,因为这会导致全局的csrf防护失效从而出现漏洞。

解决方案

在settings.py中添加

1
2
CSRF_TRUSTED_ORIGINS = ['servicewechat.com'] 
#这是微信小程序的官方服务器域名,所有请求都从这里发出

首先要使前后端能交流csrftoken和cookie:

Django后端:

1
2
3
4
5
6
7
8
9
10
# xxx/views.py
from django.middleware.csrf import get_token

def token(request):
token=get_token(request)
return JsonResponse({'token':token})

# xxx/urls.py
# 添加:
path('token', views.token)

微信js前端:

1
2
3
4
5
6
7
8
9
function getToken(callback) {
wx.request({
url: DBPath + 'token',
success:(res)=>{
if(callback)
callback(res);
}
});
}

在小程序启动或者登录的时候向后端发送获取csrftoken的请求

1
2
3
4
5
6
7
getToken((res)=>{
console.log(res)
let temp = (res.cookies[0].split(';')[0]).split('=')[1];
//split(';')[0]是因为csfttoken总是被django放在最前面
wx.setStorageSync('csrftoken', res.data.token);
wx.setStorageSync('cookie', res.header['Set-Cookie']);
})

在js的POST请求中添加请求头(以wx.uploadFile为例):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
wx.uploadFile({
filePath: path,
name: 'file',
header: { //必须包含cookie和X-CSRFToken
'content-type': 'application/x-www-form-urlencoded',
//上网找的解决方案都缺少这个cookie,我这边必须加上这个
//否则csrf cookie not set
'cookie': wx.getStorageSync('cookie'),
'X-CSRFToken': wx.getStorageSync('csrftoken')
},
formData:{
...
},

url: DBPath + 'upload-avatar',
}

【Django+微信小程序】前后端分离跨站点POST请求踩坑实录
https://chordfish-k.github.io/2023/05/15/django-20230515/
作者
超弦鱼
发布于
2023年5月15日
许可协议