Django+微信小程序开发待办清单:通讯和登录

3464 views, 2022/01/25 updated   Go to Comments

开发 Web 版 Todo-List,首先需要解决两个问题:

  • 建立小程序和 Django 之间的通讯,这是一切工作的基础。
  • 建立用户登录机制,以区分后端中数据的归属。

本章就来解决通讯问题,并分步骤搞定登录问题。

Django接口

学过 Django 的同学都知道,Django 项目是以 App 的形式组织起来的。所以第一步就是万年不变的创建 App 了。

在 backend 路径开启命令行,输入下面的神秘文字:

(venv) backend> python manage.py startapp weixin

创建了个叫 weixin 的 App。

现在你的后端目录结构应该是这样的:

backend/
  -- manage.py

  -- backend/
    -- ...

  -- weixin/
    -- migrations/
    -- __init__.py
    -- admin.py
    -- apps.py
    -- models.py
    -- tests.py
    -- views.py

如果你读过我以前的系列文章 Django搭建个人博客 或者 Django-Vue 搭建个人博客,应该就对 App 中生成的这些文件相当熟悉了。

接下来在 weixin/views.py 中随便写个视图,以便测试功能:

# weixin/views.py

from rest_framework.views import APIView
from rest_framework.response import Response

class WeixinLogin(APIView):
    def get(self, request, format=None):
        """
        提供 get 请求
        """
        return Response({"data": "hello world."})

视图类 WeixinLogin() 基于 DRF 框架 APIView ,它通过实现 get() 函数,提供了一个简单的 GET 请求。

然后创建 weixin/urls.py 文件,配置子路由:

# weixin/urls.py

from django.urls import path
from weixin.views import WeixinLogin

app_name = 'weixin'

urlpatterns = [
    path('login/', WeixinLogin.as_view(), name='login'),
]

接着修改 backend/urls.py 给子路由分配上级路由:

# backend/urls.py

from django.contrib import admin
from django.urls import path, include

urlpatterns = [
    ...
    # 增加了这行
    path('api/weixin/', include('weixin.urls', namespace='weixin')),
]

最后注册 App:

# backend/settings.py

...

INSTALLED_APPS = [
    ...

    'weixin',
]

运行 runserver 服务器,在浏览器中输入地址 http://127.0.0.1:8000/api/weixin/login/

dwt-70-3

“hello world.”

小程序请求

后台能够正常返回数据了,但是还需要在小程序中获取数据。

首先准备工作。小程序为了安全起见,默认 web 请求必须具有 HTTPS 证书。本地的 runserver 显然没有此证书,因此得打开小程序开发工具右上侧的“详情”配置,勾选”不校验合法域名、web-view、TLS版本以及HTTPS证书“:

dwt-70-4

接下来写代码,向 Django 后端发送请求。还记得前面说过的小程序通用接口 wx.[xxx] 吗?它又来了,这次的作用是发请求。

修改小程序项目 pages/index/index.js 的生命周期函数,添加 wx.request() 相关代码:

// pages/index/index.js

Component({
  // ...
  lifetimes: {
    attached() {
      // ...
      wx.request({
        url: 'http://127.0.0.1:8000/api/weixin/login/',
        success(res) {
          console.log(res.data)
        }
      })
    },
  },
})

保存文件并刷新模拟器,加载完页面后,调试器中就将取得的数据打印出来了:

dwt-70-5

注意,勾选的”不校验HTTPS证书“选项仅在开发时有效。后续真正部署到线上时,记得老老实实将域名升级为 HTTPS 。

通讯算是搞定了,下面将进入本教程最核心的部分:用户登录。

登录流程图

将数据存到云端,首要问题就是要解决身份认证问题,也就是俗话说的用户登录了。

Django 和小程序的登录比较麻烦的是,用户的身份是由微信提供的(因为是微信用户嘛),所以需要小程序客户端、微信接口服务、Django后端的三方交互,并且要保证敏感数据的安全性。

看下面这个非常重要的微信官方提供的流程图:

dwt-80-1

看不懂没关系,我帮你总结下:

  • 小程序通过微信接口获取临时登录凭证Code
  • 小程序将Code发送到Django服务器。
  • Django服务器将Code发送到微信接口服务,换取openid等身份凭证
  • Django服务器将身份凭证与自身的用户建立对应关系,并返回小程序token
  • 小程序通过token请求业务数据。

接下来将分几章,逐步实现上图中的登录及业务流程。

后端获取凭证

任何第三方(比如我们的 Django 服务器)必须要提供小程序的 AppID 和 AppSecret ,才能从微信通用接口请求对应的数据。这很好理解,如果任何不经认证的第三方都能获取到用户的信息,那也太危险了。所以 AppID 和 AppSecret 是很重要的信息,只能在后台查看。

在前面的章节中,读者应该已经注册了小程序测试号了。再次从微信公众平台登录测试号:

dwt-80-2

然后就能在后台查看你的 AppID 和 AppSecret 了:

dwt-80-3

将它们记录好,接下来会用到。

然后在小程序开发工具中,确保你的账号是登录状态。后续的功能都是基于模拟器中的微信用户身份。

dwt-80-0

再看一眼开头的流程图。第一步是小程序需要向开发者服务器(即 Django 服务器)发送临时登录凭证Code

修改前端中 js 文件的 attached() 函数,使小程序启动时自动发送 Code :

// frontend/pages/index/index.js

// ...其他代码省略
// 修改 attached()

lifetimes: {
  attached() {
    wx.login({
      success(res) {
        if (res.code) {
          //发起网络请求
          wx.request({
            // 这里是django的本地ip地址
            // 如果部署到线上,需要改为接口的实际网址
            url: 'http://127.0.0.1:8000/api/weixin/login/',
            // 请求方式修改为 POST
            method: 'POST',
            data: {
              code: res.code
            }
          })
        } else {
          console.log('登录失败!' + res.errMsg)
        }
      }
    })
  },
},

前端暂时这样就 ok 了,接下来开发后端 Django 代码。

还是根据流程图,Django 收到 Code 后,需要拿着 Code 和微信接口服务通信。因此先在虚拟环境中安装网络请求库 requests

(venv) > pip install requests

完成后,修改上一章的视图类 WeixinLogin() ,使其具有真正实用的功能:

# backend/weixin/views.py

from rest_framework.views import APIView
from rest_framework.response import Response
import requests
import json

class WeixinLogin(APIView):
    def post(self, request, format=None):
        """
        提供 post 请求
        """
        # 从请求中获得code
        code = json.loads(request.body).get('code')

        # 填写你的测试号密钥
        appid = 'wxa0...42d4'
        appsecret = '7077...4a48'

        # 微信接口服务地址
        base_url = 'https://api.weixin.qq.com/sns/jscode2session'
        # 微信接口服务的带参数的地址
        url = base_url + "?appid=" + appid + "&secret=" + appsecret + "&js_code=" + code + "&grant_type=authorization_code"
        response = requests.get(url)

        # 处理获取的 openid
        try:
            openid = response.json()['openid']
            session_key = response.json()['session_key']
        except KeyError:
            return Response({'code': 'fail'})
        else:
            # 打印到后端命令行
            print(openid, session_key)
            return Response({'code': 'success'})

它做了两件事情:

  • 将 Code 发送到微信接口服务,换取到 openid 等关键身份信息。
  • 将 openid 打印到 Django 命令行中。

注意视图类现在仅接受 POST 请求了。

获取到的 openid 和 session_key 打印出来大概是这个样子:

ow5rb5.........nJbgj-hT9w    9B3Rmx.......7Yxs2/GA==

接下来的章节中我们将只用到 openid。当用户使用了微信小程序,后台会产生一个唯一的openid,可以通过这个来区分不同的用户。

会话密钥 session_key 是对用户数据进行了加密签名的密钥。注意:为了应用自身的数据安全,开发者不应该把会话密钥下发到小程序,也不应该对外提供这个密钥。

自定义登录态

拿到 openid 后,就相当于拿到当前用户的身份证号,接下来需要将 openid 和 Django 服务器自身的数据库中的用户对应起来。

修改视图类如下:

# backend/weixin/views.py

...
from django.contrib.auth.models import User

class WeixinLogin(APIView):
    def post(self, request, format=None):
        """
        提供 post 请求
        """
        ...
        # 处理获取的 openid
        try:
            ...
        except KeyError:
            ...
        else:
            # 根据openid确定用户的本地身份
            try:
                user = User.objects.get(username=openid)
            except User.DoesNotExist:
                user = None

            if user:
                user = User.objects.get(username=openid)
            else:
                user = User.objects.create(
                    username=openid,
                    password=openid
                )
            return Response({'code': 'success'})
  • 如果存在用户名为 openid 的用户,则将其取出。
  • 如果不存在,则新建用户名为 openid 的用户,并取出。

这里对数据库进行了多次查询,你可以尝试优化一下。

这样就可以了!试试多次重启小程序,Django后端将随之自动在数据库中创建或搜索对应的本地用户。

你可以在 Django 后台中确认。创建超级用户:

(venv) > python manage.py createsuperuser

浏览器访问 http://127.0.0.1:8000/admin/ 登录后台,查看 User

dwt-80-4

下面那个就是通过 openid 创建的用户了。

总结

对比开头那个流程图,我们已经把用户登录上半部分给搞好了。

接下来的章节整用户登录下半部分,继续走起。

点赞 or 吐槽?来博客GitHub评论区!




本文作者: 杜赛
发布时间: 2022年01月25日 - 22:15
最后更新: 2022年01月25日 - 22:15
转载请保留原文链接及作者