实战小程序登录

对于小程序的登录流程,相信大家都不陌生。无论是在学习过程中,还是开发过程中,你们肯定看见过:

具体的网址在:developers.weixin.qq.com/miniprogram...

总结简单的步骤:

  1. 前端调用wx.login() 获取到 code,将 code 传递给后端。
  2. 后端拿取到 code,以及其他的额外参数(appid、 appsecret),调用微信接口服务端(https://api.weixin.qq.com/sns/jscode2session)
  3. 微信接口服务端返回 openid 和 session_key 等信息,后端接受后,生成自定义 token (jwt),用来登录标识。
  4. token 返回前端,存储在本地,后面的接口都带上 token,用于信息验证。

这就是大致的流程,也很容易理解,接下来就来实际操作演练一下。

小程序端

因为以前没有写过小程序,在获取用户信息,还发生了一点小插曲。

wx.getUserProfile() 代替了 wx.getUserInfo() 来获取用户信息。这里也详细解释了一下为什么替换

自己也顺便的去尝试了一下,主要在两点的区别:

  1. wx.getUserProfile() 会弹出授权弹窗;而 wx.getUserInfo() 没有
  2. wx.getUserInfo() 获取的用户信息都是默认值(匿名值);wx.getUserProfile() 获取的真实用户信息。

进入正题。

html 复制代码
<button bindtap="getUserProfile">获取用户信息</button>
js 复制代码
Page({
  data: {
    userInfo: {}
  },
  async getUserProfile() {
   // 获取用户信息
   const profileRes = await wx.getUserProfile({
     desc: '用于授权',
   })
   const { encryptedData, iv, userInfo } = profileRes
   this.setData({userInfo})
​
   // wx.login 获取 code(有效期 5min)
   const loginRes = await wx.login()
   const { code } = loginRes
   
   // 发送网络请求
   let params = {
     code,
     encryptedData,
     iv
   }
   wx.request({
     url: 'http://localhost:3000/auth',  // 本地启动一个服务
     data: params,
     method: 'POST',
     success: function(res) {
      console.log(res)
     }
   })
  }
})

为什么这里需要单独解构出 encryptedDataiv 呢?

  • 加密数据encryptedData 接口如果涉及敏感数据(如 openId 或者 unionId),接口的明文内容将不包含这些敏感数据。开发者如需要获取敏感数据,则需进行解密。
  • iv 是加密算法的初始向量

这两者传递给后端,配置 session_key 进行解密。

服务端

这里就使用 express 进行服务器搭建吧(本来这里还想用 nestjs 进行搭建的,那么就搞得代码复杂化)

最近在学习 nestjs,,有没有大佬带带我~~~

bash 复制代码
# 初始化
npm init
​
# 安装依赖: axios 用于请求微信接口服务端
pnpm add express axios

axios 内部实现是区分两种环境的:

  • 浏览器,是基于 XMLHttpRequest 实现的
  • node端,是基于 http模块 实现的

简单搭建一个服务器。

js 复制代码
const express = require("express");
​
const app = express();
app.use(express.json()); // 用户解析 post 参数,添加到 req.body 上
​
app.post("/auth", (req, res) => {
  res.json({
    message: 'success',
    code: 200
  })
});
​
app.listen(3000, () => {
  console.log("The server is running!!!");
});

通过上面的简单搭建之后,通过 node index.js 来测试接口是否通。(当然这里更推荐 nodemon,不然每次更改后,都要手动去重新运行)

如果接口成功之后,就来写里面的逻辑。里面的逻辑大致步骤为:

  1. 获取一些参数(code,appid, appsecret)
  2. 请求微信接口服务端
  3. 解密,拿取用户信息,自定义登录标识。

可以先看看微信提供接口的整体结构

微信服务的接口信息:developers.weixin.qq.com/miniprogram...

其中针对参数 appidsecret 需要自己手动拿取,如下:

小程序开放平台:mp.weixin.qq.com/wxamp/devpr...

拿到参数之后,,,

js 复制代码
const express = require("express");
const axios = require("axios");
​
const app = express();
app.use(express.json());
​
app.post("/auth", (req, res) => {
  const { encryptedData, iv, code } = req.body;
  const appid = "xxxxx"; // 替换成自己的
  const secret = "yyyyyy";
  const grant_type = "authorization_code";
  
  // 组装请求地址
  let url = `https://api.weixin.qq.com/sns/jscode2session?appid=${appid}&secret=${secret}&js_code=${code}&grant_type=${grant_type}`;
  
  // 发送请求
  axios.get(url).then((axiosRes) => {
    // 就会拿到 session_key, openid,针对 unionid 如果小程序已绑定到微信开放平台账号下则会返回(这里就没有返回)
    const { session_key, openid } = axiosRes.data;
    // 解密
    const info = decode(encryptedData, iv, session_key)
  });
});
​
app.listen(3000, () => {
  console.log("The server is running!!!");
});

拿到 session_key 之后,就是对encryptedData 进行解密。这里封装了一个方法 decode

js 复制代码
const crypto = require("crypto");
​
function decode(encryptedData, iv, session_key) {
  // 解密
  const session_key_base64 = Buffer.from(session_key, "base64");
  const encryptedData_base64 = Buffer.from(encryptedData, "base64");
  const iv_base64 = Buffer.from(iv, "base64");
​
  /**
   * crypto.createDecipheriv() 是 Node.js 中的一个加密解密方法,用于创建一个解密器对象。它可以使用指定的算法和密钥对数据进行解密,并且支持使用初始化向量(IV)来提高解密的安全性。
   * 创建解密器对象
   * algorithm: 加密算法,例如 aes-256-cbc
   * key: 解密密钥,必须是一个 Buffer 类型或者字符串类型
   * iv: 初始化向量,必须是一个 Buffer 类型或者字符串类型
   */
  const decipher = crypto.createDecipheriv(
    "aes-128-cbc",
    session_key_base64,
    iv_base64
  );
  /**
   * setAutoPadding() 方法用于控制解密时是否自动进行填充操作。
   * 如果设置为 false,则需要手动处理填充;
   * 如果设置为 true(默认值),则会自动进行填充。
   * 对称加密算法通常需要进行填充以满足特定的块大小要求。
   */
  decipher.setAutoPadding(true);
  
  // update 方法用于输入加密数据
  let decoded = decipher.update(encryptedData_base64, "binary", "utf-8");
  
  // final 方法用于获取解密后的结果
  decoded += decipher.final("utf-8");
​
  return JSON.parse(decoded);
}

接下来只需要调用 decode 方法,就可以得到类似如下格式的数据:

拿到用户信息之后,就可以做自己的一些业务逻辑了。 比如使用 jwt 生成 token,在 payload 里面保存着上面的信息。

回顾

在前端方面,使用 wx.getUserProfile() 获取 encryptedDataiv;使用 wx.login() 获取 code。然后把这三个参数传递给后端。

在后端方面,首页就是需要去拿取 appidappsecret,然后再拿取前端传递过来的 code 去调用微信接口服务提供的接口(jscode2session)。

微信接口服务返回了 secret_keyopenid 等信息

拿到 secret_key,再配和 crypto 内置库,对 encryptedData 进行解密,拿到用户信息。

最后就是处理自己的业务逻辑,比如生成 token 等等。

相关推荐
HEX9CF10 分钟前
【CTF Web】Pikachu xss之href输出 Writeup(GET请求+反射型XSS+javascript:伪协议绕过)
开发语言·前端·javascript·安全·网络安全·ecmascript·xss
凌云行者22 分钟前
使用rust写一个Web服务器——单线程版本
服务器·前端·rust
华农第一蒟蒻39 分钟前
Java中JWT(JSON Web Token)的运用
java·前端·spring boot·json·token
积水成江40 分钟前
关于Generator,async 和 await的介绍
前端·javascript·vue.js
___Dream41 分钟前
【黑马软件测试三】web功能测试、抓包
前端·功能测试
金灰41 分钟前
CSS3练习--电商web
前端·css·css3
人生の三重奏1 小时前
前端——js补充
开发语言·前端·javascript
计算机学姐1 小时前
基于SpringBoot+Vue的高校运动会管理系统
java·vue.js·spring boot·后端·mysql·intellij-idea·mybatis
Tandy12356_1 小时前
js逆向——webpack实战案例(一)
前端·javascript·安全·webpack
TonyH20021 小时前
webpack 4 的 30 个步骤构建 react 开发环境
前端·css·react.js·webpack·postcss·打包