Express实战个人订阅号实现网站登录
今天我们来实现一个使用个人订阅号实现网站的功能,后端使用的是 express 。其它框架原理基本一致,只是定义路由或返回响应数据部分代码跟 express 有所出入。先来一波效果图:
1. 前言
20 年 3 月在掘金写过一篇文章,介绍了使用 express 开发微信公众号的案例: 原文地址。当时使用的 nodejs 版本还是 v8.x,现如今,nodejs 的最新长期稳定版已经来到了 v18.16.0, 新特性尝鲜版更是已经到了 v20.1.0。
不得不感慨时间之飞逝,nodejs 的版本升级之路见证了技术的飞速进步,也见证了我发际线的飞速退后。
......
2. 为何要用订阅号去登录
看了看掘金,发现掘金的登录注册分为两种:
- 手机号验证码注册
- 第三方登录(支持微信扫码、微博、Github)
企业站来说,这种方式固然好,给了用户提供了更多的选择。
但是对于个人站点,这种方式就不太友好了,因为:
手机号接收验证码注册:1 条短信 1 毛钱,10 条就是 1 块,100 条就能吃个豪华早餐了
接入微信开放平台是需要企业资质的。我一个打工人,上哪儿去搞企业资质?这就是一道坎,更别说后续接入的繁琐流程了。
Github 倒是不需要,不过接入也麻烦,弃之!
微博?用户没有微博账号是不是还得去注册个微博账号?弃!
那就普通的注册吧?填写用户名、密码、确认密码、输入邮箱,邮箱验证码确认?弃!
那么,它来了!订阅号注册免费,花极少的时间去接入
用户只需关注公众号,反手输入个登录,回车!Ctrl + CV。欸,很快啊,登录成功!
相对于传统的注册填一大堆资料 + 确认密码 + 验证码,孰好孰坏,熟快熟慢,一试便知。
而且,且看下图,它对于保护用户隐私来说,是极好的,因为开发者只能拿到用户的 OpenID,头像和昵称都不给你!
不过, 有 OpenID 就足够了,毕竟它对于当前公众号来说,是 唯一的
3. 公众号后台配置
完整的接入指南详见: https://developers.weixin.qq.com/doc/offiaccount/Basic_Information/Access_Overview.html
进入微信公众平台
设置与开发 -> 基本配置 -> 公众号开发信息 -> IP 白名单中配置你的服务器 IP
设置与开发 -> 基本配置 -> 服务器配置(未开启的需要先开启)
URL是你的后端服务对应验证授权的接口地址,也就是你后端服务部署后绑定了域名的接口地址。举例:https://www.xxx.com/wechatToken这块的Token按照平台提示的规则自定义即可,注意,需要和上面代码中的Token相对应,不然会验证不成功。EncodingAESKey是消息加解密密钥,这个可以随机生成,也可以自定义消息加解密方式选择明文模式即可
填写好上面这些内容之后,我们先不必急着点击提交,因为这个时候服务还没部署,服务器是无法正常响应微信服务器的验证请求,必然会提交失败。
且看下文
4. 登录流程梳理
我们简单的梳理一下登录流程:
首先是需要在网站需要登录的地方,放置一个公众号的二维码,并用醒目的文字给用户提示:关注公众号后发送 "登录" ,获取登录所需要的验证码
后台接收到用户请求,判断用户发送的内容的确是 "登录" 关键字,返回一个验证码给用户,并将当前验证码存起来
用户输入验证码,后台根据存起来的验证码进行验证,验证成功,返回登录成功,否则,登录失败
5. 定义服务端路由,处理验证逻辑及服务端部署
5.1 定义授权验证接口
主要是验证消息的确来自微信服务器
import express from "express";
import jsSHA from "jssha";
const router = express.Router();
router.get("/wechat_mp", (req, res, next) => {
const token = "这里是自定义Token,可自定义,内容规则详见下文";
//1.获取微信服务器Get请求的参数 signature、timestamp、nonce、echostr
const { signature, timestamp, nonce, echostr } = req.query;
//2.将token、timestamp、nonce三个参数进行字典序排序
const array = [token, timestamp, nonce].sort();
//3.将三个参数字符串拼接成一个字符串进行sha1加密
const tempStr = array.join("");
const shaObj = new jsSHA("SHA-1", "TEXT");
shaObj.update(tempStr);
const scyptoString = shaObj.getHash("HEX");
//4.开发者获得加密后的字符串可与signature对比,标识该请求来源于微信
if (signature === scyptoString) {
console.log("验证成功");
res.send(echostr);
} else {
console.log("验证失败");
res.send("验证失败");
}
});
5.2 处理用户 "登录" 消息
接下来我们定义用户发送消息的逻辑:
当用户发送文本消息给公众号的时候,微信服务器会将用户发送的消息以 XML格式 的参数去请求这个接口,只不过这个时候,我们需要通过 POST 请求来接收参数。
先上代码:
定义POST接口
import { parseString } from "xml2js";
import myCache from "../store";
/**
* 随机6位验证码
*/
function randomCode() {
return Math.random().toString().slice(-6);
}
/**
* 回复文字消息封装
*/
function sendTextMsg(toUser, fromUser, content) {
let resultXml = "<xml><ToUserName><![CDATA[" + fromUser + "]]></ToUserName>";
resultXml += "<FromUserName><![CDATA[" + toUser + "]]></FromUserName>";
resultXml += "<CreateTime>" + new Date().getTime() + "</CreateTime>";
resultXml += "<MsgType><![CDATA[text]]></MsgType>";
resultXml += "<Content><![CDATA[" + content + "]]></Content></xml>";
return resultXml;
}
router.post("/wechat_mp", function (req, res) {
var buffer = [];
req.on("data", function (data) {
buffer.push(data);
});
// 内容接收完毕
req.on("end", function () {
var msgXml = Buffer.concat(buffer).toString("utf-8");
parseString(msgXml, { explicitArray: false }, function (err, result) {
if (err) throw err;
result = result.xml;
const { ToUserName, FromUserName, MsgType, Content } = result;
if (MsgType === "text" && Content === "登录") {
const code = randomCode();
// 这里的FromUserName就是用户的OpenID
myCache.set(code, FromUserName, 1 * 60 * 5);
const sendXml = sendTextMsg(
ToUserName,
FromUserName,
`您的登录验证码是:${code} , 有效期为5分钟`
);
res.send(sendXml);
}
});
});
});
store/index.js
import NodeCache from "node-cache";
const myCache = new NodeCache();
export default myCache;
代码解释:
XML 解析:可以通过安装
xml2js这个库来解析XML格式的参数接化发:检测到用户发送
消息类型为text且内容为登录关键字的时候,我们去生成一个6位随机验证码,再将验证码和用户的OpenID以key(code)、value(OpenId)的格式存入 存入node-cache中,并设置有效期为5分钟,同时将随机验证码发送给用户。
5.3 处理网站登录逻辑
上一步,用户已经在微信公众号上获取到了随机验证码,现在只需要在网站需要登录的地方输入验证码,调用验证码校验接口即可进行校验。
定义验证码校验接口
import myCache from "../store";
router.get("/verify", async function (req, res) {
const { code } = req.query;
const OpenID = myCache.get(code);
if (OpenID) {
const token = "使用OpenID进行jwt鉴权颁发Token";
res.json({
code: 200,
data: { token },
});
} else {
res.json({
code: 400,
msg: "您输入的验证码有误或已过期,请重新输入!-_-",
});
}
});
代码解释:
根据用户输入的验证码,去 node-cache 中获取 OpenID,如果存在,则说明验证码正确,jwt 鉴权颁发 Token。反之,校验失败。
验证码校验成功后,通过唯一的 OpenID 和自定义的 secret 给用户颁发 Token,用户再次访问网站的时候,只需要携带 Token 即可进行鉴权。
关于 jwt 鉴权概念、流程及使用,大家可以参考这条 AI 问答分享:
我在ChatGPTer(https://ai.iiter.cn)网站上创建了一个AI对话分享,快来看看吧!
「jwt鉴权概念、流程」
链接:https://ai.iiter.cn/#/share/6465c5a2e82a696c417bbfa9
同时,也欢迎大家自己进行 AI 问答: https://ai.iiter.cn
5.4 部署服务
服务部署这块大家可以参考我之前写的一篇傻瓜式部署文章:宝塔面板结合 pm2 进程管理工具部署前端项目
当然,您也可以使用自己顺手的部署方式
5.5 提交公众号配置
服务部署成功后,回到我们的 公众号后台配置 部分,点击提交即可
结语
至此,我们的个人订阅号登录功能就已经完成了,相信基于以上,大家都可以很快的去做出一个网站登录功能出来
而且在给用户提供服务的同时,可以直接将用户引导至自己的公众号上。不管是后面对网站的更新记录,还是一些重要的通知,都可以通过公众号进行消息推送,一举两得
好了,今天的文章分享就到这里了,如果对大家有所帮助的话,希望您不要吝啬手中的赞呦~
正式给大家介绍一下:
基于 OpenAI 的 API 开发的一款 ChatGPT 网站,模型是gpt-3.5-turbo,使用的是本篇文章的同款登录方式,欢迎大家体验
免费!免费!免费!https://ai.iiter.cn
Express实战个人订阅号实现网站登录的更多相关文章
- 微信订阅号里实现oauth授权登录,并获取用户信息 (完整篇)
摘要 这段时间一直有人问我,订阅号实现的oauth授权登录的问题,之前写的比较简单,很多人不明白.众所周知,微信公众号分订阅号.服务号.企业号:每个号的用途不一样,接口开放程度也不一样.微信还有个扯淡 ...
- 搭建开发框架Express,实现Web网站登录验证
NodeJS学习笔记(一)——搭建开发框架Express,实现Web网站登录验证 JS是脚本语言,脚本语言都需要一个解析器才能运行.对于写在HTML页面里的JS,浏览器充当了解析器的角色.而对于需 ...
- PHP版微信公共平台消息主动推送,突破订阅号一天只能发送一条信息限制
2013年10月06日最新整理. PHP版微信公共平台消息主动推送,突破订阅号一天只能发送一条信息限制 微信公共平台消息主动推送接口一直是腾讯的私用接口,相信很多朋友都非常想要用到这个功能. 通过学习 ...
- discuz论坛与其它网站登录注册整合
discuz论坛与其它网站登录注册整合 本文以discuz 7.0.0 php版本的论坛与 .net 2.0的网站注册登录整合为类.没有采用uc_center或第三方插件.以另类的方式实现.此方法实现 ...
- 微信小程序、应用号、订阅号、服务号、企业号小总结
微信小程序是现在微信推出的一个新的项目,但是很多人都不是很清楚微信小程序是怎么一回事,不明白到底怎样分别微信小程序和别的公众号.订阅号等的区别,那么让小编来给你介绍一下. 微信小程序目前是内侧阶段,是 ...
- PHP语言开发微信公众平台(订阅号)之注册
1.百度搜索"微信公众平台" 2.选择微信公众平台官网并单击打开 3.进入官网页面,单击 "立即注册" 进入注册页面 4.进入注册页面,单击订阅号 5.进入订阅 ...
- 升讯威微信营销系统开发实践:订阅号和服务号深入分析( 完整开源于 Github)
GitHub:https://github.com/iccb1013/Sheng.WeixinConstruction因为个人精力时间有限,不会再对现有代码进行更新维护,不过微信接口比较稳定,经测试至 ...
- PHP语言开发微信公众平台(订阅号)之注册(1)
1.百度搜索"微信公众平台" 2.选择微信公众平台官网并单击打开 3.进入官网页面,单击 "立即注册" 进入注册页面 4.进入注册页面,单击订阅号 5.进入订阅 ...
- 手把手教你基于CentOS8搭建微信订阅号后台服务(一)
一.准备域名并完成解析 关于域名,我买的是阿里的一个1元/年的廉价域名,同时国内域名都需要备案,当时在这里耽搁了挺久的. 域名解析的话,在阿里云官方帮助文档里有.传送门:https://help.al ...
- 【Vue3+Express实战】项目开发环境搭建
大家好,我是半夏,一个刚刚开始写文的沙雕程序员.如果喜欢我的文章,可以关注 点赞 加我微信:frontendpicker,一起学习交流前端,成为更优秀的工程师-关注公众号:搞前端的半夏,了解更多前端知 ...
随机推荐
- python爬取今日的bing壁纸
#!/usr/bin/python #你要的文件夹是 E://pics// ps:没有的话帮你建一个 import requests import os from datetime import da ...
- 协程 + epoll 的两个小例子
getcontext/setupcontext/swapcontext/setcontext 方式的协程实现 #include <stdio.h> #include <stdlib. ...
- 【LeetCode贪心#12】图解监控二叉树(正宗hard题,涉及贪心分析、二叉树遍历以及状态转移)
监控二叉树 力扣题目链接(opens new window) 给定一个二叉树,我们在树的节点上安装摄像头. 节点上的每个摄影头都可以监视其父对象.自身及其直接子对象. 计算监控树的所有节点所需的最小摄 ...
- CTF-RE-学习记录-汇编
八进制运算 加法表 1+1=2 1+2=3 2+2=4 1+3=4 2+3=5 3+3=6 1+4=5 2+4=6 3+4=7 4+4=10 1+5=6 2+5=7 3+5=8 4+5=11 5+5= ...
- SimpleAdmin手摸手教学之:项目架构设计2.0
一.说明 在SimpleAdmin1.0版本中,我将整体项目结构分为三大块,分别为架构核心.业务模块和应用服务.随着1.0版本的封版,回去再看我之前的项目架构,也暴露了一些问题,比如在1.0版本中,S ...
- python内置模块之ctype
ctypes --- Python 的外部函数库¶ ctypes 是 Python 的外部函数库.它提供了与 C 兼容的数据类型,并允许调用 DLL 或共享库中的函数.可使用该模块以纯 Python ...
- [PKM] 服务器
1 概述与基础常识 1.1 服务器的定义 定义: 服务器,英文名Server,指能提供某种服务的网络设备. 提供的主要服务包括:数据的接收和传递.数据的存储和数据的处理. 通俗点儿,我们可以把服务器比 ...
- [Java EE] java.net.SocketException: Connection reset【解决中】
1 错误描述 6:44:33.112] [DEBUG] [http-nio-9527-exec-3] [HttpClientUtil] http post url:http://bdp-gateway ...
- Gartner最新报告,分析超大规模边缘解决方案
当下,酝酿能量的超级边缘. 最近,我们在谈视频化狂飙.谈AIGC颠覆.谈算力动能不足,很少谈及边缘.但"边缘"恰恰与这一切相关,且越发密不可分,它是未来技术发展的极大影响因子. & ...
- HOOPS Exchange助力Shapr3D产品实现了“无障碍的用户体验”
HOOPS SDK是用于3D工业软件开发的工具包,其中包括4款工具,分别是用于 读取和写入30多种CAD文件格式的HOOPS Exchange.专注于Web端工程图形渲染的HOOPS Communic ...