我在这里详细表述一遍:微信小程序和具有权限认证、CSRF机制的Django服务端通信的一个可行的例子。。
本教程基于
Django
预设,在cookies
的命名和csrftoken
的接收上可能和其他语言框架的有所不同。首先要知道一些基本知识:当微信小程序在会话期间想要再次向服务端请求时,不需要再次登录,只需要把sessionid放进cookie中传递过去就可以了,以便防止跨域请求,还要携带上csrftoken。微信小程序不像浏览器那样在二次请求时会自动搬运
cookies
,cookies
需要我们自己写上。
1,微信小程序使用wx.login()
获取到code
后发送给服务端
2,服务端向微信服务器请求得到openid
和session_key
,进行处理注册登录后,通过session
记录用户登录状态,最后返回给微信小程序的cookies
有csrftoken
和sessionid
3,微信小程序二次请求时在请求上方移动cookie
,cookie
中存放上次请求得到的csrftoken
和sessionid
,并且请求头部中还要有一个X-CSRFToken
键值对。
首先在第一次登录请求时就要把csrftoken
和sessionid
获取下来,并分别保存在缓存中。(为什么要分别保存?因为等下二次请求时要分别用到)
wx.login({
success: res => {
if (res.code) {
wx.request({
url: xxx,
method: 'POST',
data: { 'code': res.code },
success: res => {
if (res.statusCode == 200) { //服务端处理正常,登录成功
//wx.setStorageSync("cookies", res.header["Set-Cookie"]); //存进去的是所有cookie串在一起的字符串,包括csrftoken和sessionid,但我们不要用这个方式,原因见下文介绍
wx.setStorageSync('csrftoken', res.cookies[0])
wx.setStorageSync('sessionid', res.cookies[1])
}
},
});
}
}
});
在上面你看到了,我在保存csrftoken
和sessionid
到缓存时,使用的是res.cookies
,而不是res.header["Set-Cookie"]
,本来微信小程序接收到的cookies
就是和res.header["Set-Cookie"]
一样的,但在二次提交时这个东西并没有想象中那样可以直接使用。。
本地缓存中已经有csrftoken
和sessionid
了,二次请求时要先处理后续两种样东西:
1,csrftoken
和sessionid
合并后的cookie
2,纯的,没有cookie
信息的csrftoken
其实第一项中的cookie
本来是可以直接用res.header["Set-Cookie"]
这个得到的cookies
字符串就可以了的,但不知道为什么,这个串联中的csrftoken
和sessionid
这两个cookie
并非用分号;
和间隔替换的,否则用一个逗号,
隔开,这个cookie
发送到后端的英文识别不出来的..
所以需要这样设计:
let cookie = wx.getStorageSync("csrftoken") + '; ' + wx.getStorageSync("sessionid")
而纯粹的,没有cookie
信息的csrftoken
又是怎么回事?
用过ajax
向Django
服务端发送请求的人都知道,在headers
中是要X-CSRFToken
填充键值对的,而在Django
的模板语言中,我们经常可以直接用X-CSRFToken:'{{ csrftoken }}'
这样的简单方式来生成纯粹的csrftoken
,但微信小程序可没有这个模板语言,而在我们保存的cookie
中的那个csrftoken
是携带着其他信息的,所以要我们去截取纯粹的csrftoken
。
截取方式:
csrftoken = wx.getStorageSync("csrftoken").split(';')[0].split('=')[1]
对这个截取方式不理解的可以展开
wx.getStorageSync("csrftoken")
看一下就明白了,其实就是对这个字符串先按分号分割然后取第一个元素再按等号分割后取第二个元素,也就是纯粹的csrftoken
。
所以我们在二次请求时,应该这样:
wx.request({
url: xxx,
data: "",
method: 'POST',
header: {
'cookie': wx.getStorageSync("csrftoken") + '; ' + wx.getStorageSync("sessionid"),
'X-CSRFToken': wx.getStorageSync("csrftoken").split(';')[0].split('=')[1]
}
})
至此,我们就实现了微信小程序携带cookie
和csrftoken
向Django服务端请求的需求。
注意:微信小程序
wx.request
的cookie
是单数,也是header
单数。