django开发小程序实现openid登录功能
侃后端django
django是一个Python栈的重型框架,可以说web开发中遇到的相关技术栈在这个框架中都能找到身影,如果说要学习PythonWeb开发,自然是绕不开的存在,如果能再深入其源码内部窥视一番,那收获绝对满满,他的架构设计思路,各种插件机制的开发,以及眼花缭乱的函数式装饰器,类装饰器等等的一些酷炫技巧,真的是让人不得不感叹一句,牛逼!
django+小程序 擦出爱情的火花
正式进入正题,实现微信小程序登录逻辑!首先我们需要搞清楚,微信小程序登录的一逻辑套路,如下图!
图:来自小程序官方文档
说明
- 调用 wx.login() 获取 临时登录凭证code ,并回传到开发者服务器。
- 调用 auth.code2Session 接口,换取 用户唯一标识 OpenID 、 用户在微信开放平台帐号下的唯一标识UnionID(若当前小程序已绑定到微信开放平台帐号) 和 会话密钥 session_key。
之后开发者服务器可以根据用户标识来生成自定义登录态,用于后续业务逻辑中前后端交互时识别用户身份。
注意事项
- 会话密钥
session_key
是对用户数据进行 加密签名 的密钥。为了应用自身的数据安全,开发者服务器不应该把会话密钥下发到小程序,也不应该对外提供这个密钥。 - 临时登录凭证 code 只能使用一次。
困惑
其实上边的图和文字都已经说的非常清楚,稍微有点概念的开发者基本上都可以读懂和看懂,但很多初学者却仍然是一脸懵逼,没有概念,什么开发者服务器,回传,换取code等等这些词汇搞懵逼了,其实代码很简单一看就,喔,原来这样啊的豁然开朗,那么就带你用代码解读上边那句话!
流程解读
前端通过wx.login() 就可以在返回值中拿到一个code也就是只能使用一次的那个code, 之后再在回调方法success()中将这个code,通过wx.request() 方法向django后端发起一个post请求,并携带这个code,这就是回传code到开发者服务器,之后在django后端构造的这个post请求中就可以获取到这个code,再携带微信小程序的appid和appsecret,向微信的这个 https://api.weixin.qq.com/sns/jscode2session 接口携带那几个参数发送get请求即可,如下所示!
https://api.weixin.qq.com/sns/jscode2session?appid={appid}&secret={appsecret}&js_code={code}&grant_type=authorization_code"
到这里基本的流程就跑通了,下面我们直接来看看前端代码和后端代码,就能够一目了然的看懂!
前端代码
wx.login({
success (res) {
// 判断是否获取到了code
if (res.code) {
// 向开发者服务器回传code
wx.request({
url: `http://127.0.0.1:8000/wechat/login/`,
method: 'POST',
data: {
code: res.code
},
success: res => {
// 拿到开发者服务器返回的用户信息及openid等逻辑需要的信息
console.log(res)
}
})
}
}
})
后端代码
class WechatLogin(APIView):
""" 获取opeid存储用户信息"""
appid = 'wxxxxxxxx'
appsecret = ''
jscode2session_url = "https://api.weixin.qq.com/sns/jscode2session"
def post(self, request, format=None):
# 获取到前端回传过来的code
code = json.loads(request.body).get('code') # 这个code有效期为5分钟
# 构造向wx发送请求的url
url = f"{self.jscode2session_url}?appid={self.appid}&secret={self.appsecret}&js_code={code}&grant_type=authorization_code"
# 向微信服务器发起get请求
response = requests.get(url)
try:
# 这里就是拿到的openid和session_key
openid = response.json()['openid']
session_key = response.json()['session_key']
except KeyError:
return Response({'code': 'fail'})
else:
# 主代码块执行完执行到这里,获取或保存用户
user, iscreated = User.objects.get_or_create(
username=openid,
password=openid,
defaults={'username': openid}
)
# 采用JWT登录的话,这里就返回token信息
from foodapi.utils import get_tokens_for_user
token_dict = get_tokens_for_user(user)
try:
userinfo = user.userinfo
except UserInfo.DoesNotExist:
userinfo, isupdated = UserInfo.objects.update_or_create(owner=user, name=openid, defaults={'owner': user})
avatar = f"http://{request.get_host()}/{str(userinfo.avatar)}"
return Response({"code": "success", "openid": openid, "name": userinfo.name, "avatar": avatar, **token_dict}, status=status.HTTP_200_OK)
到这里,这个基本的逻辑就完成了,用户信息就已经在前端可以拿到了,前端就可以把相关信息进行存储并使用状态管理来管理和获取这些信息,前端的逻辑还有很长的路要走,这里我们主要就是掩饰这个小程序登录的一个基本的流程!