node 微信小程序登录
1、申请小程序账号
1.1、 正式账号
做小程序开发之前,首先要申请账号。,可以进入小程序注册页,根据提示注册就好。

1.2. 获取 AppID 和 AppSecret
注册好后,打开微信公众平台,扫码登录。进来后,点击左侧的开发管理:

然后打开 Node 项目的.env文件,添加上两个环境变量
WECHAT_APPID=你的小程序ID
WECHAT_SECRET=你的小程序密钥
网页底部还有服务器域名的配置,暂时没有啥用,如果将来小程序要上线,就需要设置成自己的接口地址了。

1.3、 测试号
再来看测试号的注册。我们现在只是为了学习开发而已,也不用那么麻烦的做注册,可以直接申请小程序测试号,

大家按照要求的流程,申请完成后,进入微信公众平台,扫码登录

里面同样的给我们了小程序ID和密钥,也需要将这两个值填写到.env中。底下的服务器域名,可以先不管。
2、 微信小程序登录
2.1、创建微信小程序
学习做微信小程序登录,就不能直接用浏览器进行开发了,必须要下载微信开发者工具。
打开链接后,大家根据自己的操作系统,自己下载安装就好。
- Windows,一般要选第一个。
- 苹果电脑,一般要选最后一个。
初次打开,会要求登录,直接用自己的微信扫码登录。

接着再创建项目。需要先在自己电脑里,建一个文件夹,用于保存小程序项目

2.2、 微信登录原理
在开始开发之前,先来学习下微信小程序登录的原理。

获取code -> 换取 openid -> 查询/注册用户 -> 生成token
- 通过 wx.login() 获取到用户的code判断用户是否授权读取用户信息,调用wx.getUserInfo 读取用户数据
- 由于小程序后台授权域名无法授权微信的域名,所以需要自身后端调用微信服务器获取用户信息
- 通过 wx.request() 方法请求业务方服务器,后端把 appid , appsecret 和 code 一起发送到微信服务器。 appid 和 appsecret 都是微信提供的,可以在管理员后台找到
- 微信服务器返回了 openid 及本次登录的会话密钥 session_key
- 后端从数据库中查找 openid ,如果没有查到记录,说明该用户没有注册,如果有记录,则继续往下走
- session_key 是对用户数据进行加密签名的密钥。为了自身应用安全,session_key 不应该在网络上传输
- 然后生成 session并返回给小程序
- 小程序把 session 存到 storage 里面
- 下次请求时,先从 storage 里面读取,然后带给服务端
- 服务端对比 session 对应的记录,然后校验有效期
2.3、 第一步:获取 code
打开小程序的app.js文件,注意看到里面登录这里。增加上一行代码
console.log(res.code)

2.4、 第二步:换取 openid
接着,就要用这个code,换取openid了。查看小程序登录文档:

里面说明,使用GET请求,发送这四个参数过去,就能获取到openid。
appid和secret都已经有了。js_code:就是刚才获取到的code。- 最后一个参数,是一个固定的值,按照着文档填就好。
有个问题是,在 Node 代码里,没法直接发起请求。大家做前端开发的时候,都用过axios。现在在接口里,也可以用axios发起请求。
npm i axios
然后在routes目录,新建一个wechat.js文件,这个文件就专门放微信相关的代码。从讲义文档,粘贴下基础代码:
const express = require('express');
const router = express.Router();
const axios = require('axios');
const {sequelize, User, Order} = require('../../models');
const {success, failure} = require('../../utils/responses');
const {BadRequest, NotFound} = require('http-errors');
const jwt = require('jsonwebtoken');
const {v4: uuidv4} = require('uuid');
const userAuth = require('../../middlewares/user-auth');
const logger = require("../../utils/logger");
const moment = require('moment');
/**
* 微信小程序登录
* POST /wechat/sign_in
*/
router.post('/sign_in', async (req, res) => {
try {
const {code} = req.body;
// 通过 code 获取微信用户 openid
const response = await axios.get('https://api.weixin.qq.com/sns/jscode2session', {
params: {
appid: process.env.WECHAT_APPID,
secret: process.env.WECHAT_SECRET,
js_code: code,
grant_type: 'authorization_code'
}
});
const {errcode, errmsg, openid} = response.data;
if (errcode) {
throw new BadRequest('微信登录失败:' + errmsg);
}
success(res, '登录成功。', {openid});
if (!code) {
throw new BadRequest('请提供微信登录 code');
}
} catch (error) {
failure(res, error);
}
});
module.exports = router;
2.5、第三步:测试接口

2.6、第四步:数据库用户表新增openid
现在openid已经获取到了。我们要在用户表,添加一个openid字段,用于保存当前微信用户的唯一识别信息
sequelize migration:create --name add-openid-to-user
打开生成的迁移文件,直接覆盖
'use strict';
/** @type {import('sequelize-cli').Migration} */
module.exports = {
async up(queryInterface, Sequelize) {
await queryInterface.addColumn('Users', 'openid', {
type: Sequelize.STRING,
});
await queryInterface.addIndex('Users', ['openid']);
},
async down(queryInterface, Sequelize) {
await queryInterface.removeColumn('Users', 'openid');
}
};
运行一下迁移命令
sequelize db:migrate
然后修改模型,打开models/user.js文件,在字段定义部分,加上openid的定义:
User.init(
{
// 其他字段定义
openid: DataTypes.STRING,
}
);
2.7、第五步:查询/注册用户
回到路由,继续第二步,查询或注册用户:
// success(res, '登录成功。', { openid });
// 查找或创建用户
let user = await User.findOne({
where: { openid: openid }
});
if (!user) {
// 首次登录,创建新用户
const key = uuidv4();
// 微信用户无邮箱、无用户名、无密码信息,随机生成
user = await User.create({
openid: openid,
nickname: '微信用户',
email: `wx-${key}@clwy.cn`,
username: `wx-${key}`,
password: Math.random().toString(36).slice(-8),
sex: 2,
role: 0,
});
}
2.7、第六步:生成 token
// 生成 JWT token
const token = jwt.sign(
{
userId: user.id,
},
process.env.SECRET,
{ expiresIn: '30d' }
);
success(res, '登录成功。', { token });
2.8、最终测试

2.9、其他用户接口
到此,微信登录接口就搞定了。除此外,我们还需要做几个微信上,用户相关的其他接口。
/**
* 获取用户信息
* GET /wechat/me
*/
router.get('/me', userAuth, async (req, res) => {
try {
const user = await getUser(req);
success(res, '查询用户成功。', { user });
} catch (error) {
failure(res, error);
}
})
/**
* 更新用户信息
* put /wechat/update_info
*/
router.put('/update_info', userAuth, async (req, res) => {
try {
const body = filterBody(req);
const user = await getUser(req);
await user.update(body);
success(res, '更新用户信息成功。', { user });
} catch (error) {
failure(res, error);
}
});
/**
* 公共方法:查询当前用户
* @param req
* @returns {Promise<Model<any, TModelAttributes>>}
*/
async function getUser(req) {
const id = req.userId;
const user = await User.findByPk(id, {
attributes: ['id', 'nickname', 'avatar', 'sex', 'role', 'company', 'introduce']
});
if (!user) {
throw new NotFound(`ID: ${id}的用户未找到。`);
}
return user;
}
/**
* 公共方法:白名单过滤
* @param req
* @returns {{nickname: (string|*), sex: (number|*), company: *, introduce: *, avatar: *}}
*/
function filterBody(req) {
return {
nickname: req.body.nickname,
sex: req.body.sex,
company: req.body.company,
introduce: req.body.introduce,
avatar: req.body.avatar,
};
}
更多推荐



所有评论(0)