对于小程序的登录流程,相信大家都不陌生。无论是在学习过程中,还是开发过程中,你们肯定看见过:
具体的网址在:developers.weixin.qq.com/miniprogram...
总结简单的步骤:
- 前端调用
wx.login()
获取到 code,将 code 传递给后端。 - 后端拿取到
code
,以及其他的额外参数(appid、 appsecret),调用微信接口服务端(https://api.weixin.qq.com/sns/jscode2session
) - 微信接口服务端返回 openid 和 session_key 等信息,后端接受后,生成自定义 token (
jwt
),用来登录标识。 - token 返回前端,存储在本地,后面的接口都带上 token,用于信息验证。
这就是大致的流程,也很容易理解,接下来就来实际操作演练一下。
小程序端
因为以前没有写过小程序,在获取用户信息,还发生了一点小插曲。
wx.getUserProfile()
代替了 wx.getUserInfo()
来获取用户信息。这里也详细解释了一下为什么替换。
自己也顺便的去尝试了一下,主要在两点的区别:
wx.getUserProfile()
会弹出授权弹窗;而wx.getUserInfo()
没有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)
}
})
}
})
为什么这里需要单独解构出 encryptedData
和 iv
呢?
加密数据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
,不然每次更改后,都要手动去重新运行)
如果接口成功之后,就来写里面的逻辑。里面的逻辑大致步骤为:
- 获取一些参数(code,appid, appsecret)
- 请求微信接口服务端
- 解密,拿取用户信息,自定义登录标识。
可以先看看微信提供接口的整体结构
微信服务的接口信息:developers.weixin.qq.com/miniprogram...
其中针对参数 appid
和 secret
需要自己手动拿取,如下:
小程序开放平台: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()
获取 encryptedData
和 iv
;使用 wx.login()
获取 code
。然后把这三个参数传递给后端。
在后端方面,首页就是需要去拿取 appid
和 appsecret
,然后再拿取前端传递过来的 code
去调用微信接口服务提供的接口(jscode2session
)。
微信接口服务返回了 secret_key
和 openid
等信息
拿到 secret_key
,再配和 crypto
内置库,对 encryptedData
进行解密,拿到用户信息。
最后就是处理自己的业务逻辑,比如生成 token 等等。