小程序登录流程

一、前端后端(完整模拟)

需要安装的依赖

express、mongoose、axios、nodemon

package.json

{
  "name": "code-express",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "dev": "nodemon ./main.js"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "dependencies": {
    "axios": "^1.3.4",
    "crypto": "^1.0.1",
    "express": "^4.18.2",
    "jsonwebtoken": "^9.0.0",
    "mongoose": "^7.0.0"
  },
  "devDependencies": {
    "nodemon": "^2.0.20"
  }
}

小程序登录详细步骤(直接在vs code上模拟)

//使用 Express,我们可以方便、快速的创建 Web 网站的服务器或 API 接口的服务器。
const express = require("express");
const mongoose = require("mongoose");
const jwt = require("jsonwebtoken");
const WXBizDataCrypt = require("./utils/WXBizDataCrypt");
const axios = require("axios");
// 数据库链接地址
const dburl = "mongodb://127.0.0.1:27017/hello";

// 描述数据表的格式
const schema = new mongoose.Schema({
  username: String,

  password: String,

  phone: String,

  openid: String,

  // 微信昵称
  nickName: String,

  // 微信头像
  avatarUrl: String,

  // 性别
  gender: Number,
});

// 用于操作users表的model对象
const userModel = mongoose.model("user", schema);

const appid = "wx7ebb4519149403ff";
const appSecret = "13655691c054c1b84484cbc523c78afc";

const app = express();

// 注册中间件,让req.body可以使用
app.use(express.json());

// 登录接口
app.post("/api/auth/login", async (req, res) => {
  // 1. 获取前端传递过来的 code 、encryptedData、iv
  const { code, encryptedData, iv } = req.body;

  // 2. 调用 微信的 jscode2session 接口 https://developers.weixin.qq.com/miniprogram/dev/OpenApiDoc/user-login/code2Session.html
  const response = await axios.get(
    "https://api.weixin.qq.com/sns/jscode2session",
    {
      params: {
        appid, // 小程序appid
        secret: appSecret, // 要注意安全
        js_code: code,
        grant_type: "authorization_code",
      },
    }
  );

  // 3. 取出 openid、session_key
  const { openid, session_key } = response.data;
  // const openid = "oKWcP0ZKMAk5KuUFgsLyBRtAFt08";
  console.log("openid", openid);

  // 4. 判断 openid 是否正确获取到了
  if (!openid) {
    return res.send({
      status: response.data.errcode,
      msg: response.data.errmsg,
    });
  }

  // 5. 根据 openid 去查看数据库中有没有存在
  const userInfo = await userModel.findOne({ openid });

  // 6. 判断 userInfo 是否存在
  if (!userInfo) {
    // 解密 encryptedData
    const pc = new WXBizDataCrypt(appid, session_key);
    const data = pc.decryptData(encryptedData, iv);
    console.log("解密后的数据", data);
    // 直接给注册一下,写入数据库
    await userModel.create({
      username: "",
      password: "",
      phone: "",
      nickName: data.nickName,
      avatarUrl: data.avatarUrl,
      gender: data.gender,
      openid: openid,
    });
  }

  // 7. 签发token
  const token = jwt.sign(
    {
      openid,
    },
    "hello"
  );

  // 8. 登录成功, 响应token到前端
  res.send({
    status: 0,
    msg: "登录成功",
    data: token,
  });
});

// 获取用户信息接口
app.get("/api/profile", async (req, res) => {
  try {
    // 1. 从请求头中,获取前端传递过来的 token
    const token = req.get("Authorization");

    // 2. 校验 token
    const payload = jwt.verify(token, "hello");
    console.log("payload", payload);

    // 3. 根据 openid 查询数据库对应的用户信息
    // const { password, ...other } = await userModel.findOne({
    //   openid: payload.openid,
    // });
    const userInfo = await userModel.findOne({
      openid: payload.openid,
    });

    // 4. 响应用户数据出去
    res.send({
      status: 0,
      msg: "获取成功",
      data: userInfo,
    });
  } catch (error) {
    // token 校验失败
    res.send(401, {
      status: -1,
      msg: "token 无效",
    });
  }
});

app.listen(3000, async () => {
  // 链接数据库
  await mongoose.connect(dburl);

  console.log("数据库链接成功,服务启动成功, 3000");
});