nodeJs+jwt实现小程序tonken鉴权
nodeJs+jwt实现小程序tonken鉴权
自我记录
config\config.js
// 配置文件
module.exports = {DBHOST: '127.0.0.1',DBPORT: '27017',DBNAME: 'test',secret: 'xxxxx',// 小程序的appSecretAppID: 'xxxxx',// 小程序的appId
}
token中间件
middlewares\checkTokenMiddleware.js
//导入 jwt
const jwt = require('jsonwebtoken');
//读取配置项
const {secret} = require('../config/config');
//声明中间件
module.exports = (req, res, next) => {//获取 token 采用的是 Bearer + ' ' + token形式const Authorization = req.get('Authorization');//判断if (!Authorization) {return res.json({code: 401,msg: '暂无权限',data: null})}//校验 tokenconst token = Authorization.split(' ')[1]jwt.verify(token, secret, (err, data) => {//检测 token 是否正确if (err) {return res.json({code: 403,msg: 'token失效',data: null})}//保存用户的信息req.user = data; // req.session req.body//如果 token 校验成功next();});
}
routes路由文件
routes\user.js
const express = require('express');
const router = express.Router();//导入 用户路由函数
const user_handler = require('../router_handler/user');
// 注册新用户
router.post('/reguser', user_handler.reguser);//登录操作TODO
router.post('/login', user_handler.login);
//退出登录TODO
router.post('/logout',user_handler.logout );module.exports = router;
user路由函数
router_handler\user.js
//导入 用户的模型
const UserModel = require('../models/UserModel');
//导入配置文件
const { secret, AppID } = require('../config/config')
//导入 jwt
const jwt = require('jsonwebtoken');
//导入请求
const request = require('request')
//导入 shortid
const shortid = require('shortid');
//注册用户
exports.reguser = async (req, res) => {try {const js_code = req.body.code;if (!js_code) {return res.json({code: 400,message: '缺少 js_code 参数'});}// 发送请求并处理响应sendRequest(js_code, handleResponse(res));} catch (err) {console.error('Error registering user:', err);res.json({code: 400,msg: '注册失败,请稍后再试~~',data: null});}
}const sendRequest = (js_code, callback) => {request(`https://api.weixin.qq.com/sns/jscode2session?appid=${AppID}&secret=${secret}&js_code=${js_code}&grant_type=authorization_code`, callback);
}const handleResponse = (res) => {return async (error, response, body) => {if (error) {console.error('Error sending request:', error);return res.json({code: 500,message: '请求失败,请稍后再试~~'});}if (response.statusCode !== 200) {return res.json({code: 400,message: '获取用户信息失败'});}try {const bodyInfo = JSON.parse(body);const openId = bodyInfo.openid;if (!openId) {return res.json({code: 400,msg: 'code失效',data: null});}const userData = await UserModel.findOne({ openId });if (userData) {const token = await getToken(userData.openId, userData.id)const result = await UserModel.updateOne({ id: userData.id }, { token: token })if (!result.acknowledged) {throw new Error('写入操作未被确认');}return res.json({code: 200,msg: '该用户已存在并生成新的token',data: token});}const id = shortid.generate()const token = await getToken(openId, id)const data = await UserModel.create({ openId, token, id });res.json({code: 200,msg: '获取成功',data: data.token});} catch (err) {console.error('Error registering user:', err);res.json({code: 400,msg: '注册失败,请稍后再试~~',data: null});}};
}
// 创建当前用户的 token
const getToken = async (openId, id) => {return await jwt.sign({openId,id}, secret, {expiresIn: 60 * 60 * 24 * 7});
}// 登录待测试
exports.login = async (req, res) => {try {// 获取用户名和密码const { openId } = req.body;// 查询数据库const data = await UserModel.findOne({ openId });// 判断 dataif (!data) {return res.json({code: 400,msg: '用户名或密码错误',data: null});}// 创建当前用户的 tokenconst token = await getToken(data.openId, data.id)// 响应 tokenres.json({code: 200,msg: '登录成功',data: token});} catch (err) {// 处理错误console.error('Error logging in:', err);res.json({code: 500,msg: '登录失败',data: null});}
}
// 退出待测试
exports.logout = async (req, res) => {try {// 销毁 tokenawait new Promise((resolve, reject) => {req.token.destroy((err) => {if (err) {reject(err);} else {resolve();}});});// 响应退出成功res.json({code: 200,msg: '退出成功',data: null});} catch (err) {// 处理错误console.error('Error logging out:', err);res.json({code: 500,msg: '退出失败',data: null});}
}
权限相关
展示openId 对应用户的书籍信息
书籍路由文件
routes\book.js
const express = require('express')const router = express.Router()// 导入路由函数
const book_handler = require('../router_handler/book')
// 导入验证token的中间件
const checkTokenMiddleware = require('../middlewares/checkTokenMiddleware')
// 一个路由的组成有 请求方法 , 路径 和 回调函数 组成
// app.<method>(path,callback)
// 注册新书籍
router.post('/addbook',checkTokenMiddleware, book_handler.addBook)
// 获取列表
router.get('/getBook',checkTokenMiddleware, book_handler.getBook);// 获取单独的
router.get('/book/:id',checkTokenMiddleware, book_handler.getOneBook);// 删除单独的
router.delete('/book/:id',checkTokenMiddleware, book_handler.delBook);module.exports = router
书籍路由函数
router_handler\book.js
const BookModel = require('../models/BookModel');
// 单条新增
exports.addBook = async (req, res) => {try {const data = await BookModel.create({...req.body, user: req.user.openId})return res.json({ code: 200, message: "添加成功", data: data });} catch (err) {// 处理错误并打印错误信息// 处理错误并返回失败的 JSON 响应console.error("Error creating book:", err);return res.json({ code: 500, message: "添加失败", error: err.message });}
}
// 获取列表
exports.getBook = async (req, res) => {try {const data = await BookModel.find({ user: req.user.openId })return res.json({ code: 200, message: "查询成功", data });} catch (err) {console.error("Error creating book:", err);return res.json({ code: 500, message: "查询失败", error: err.message });}
}
// 获取ID
exports.getOneBook = async (req, res) => {let { id } = req.params;let { openId } = req.usertry {const data = await BookModel.findOne({ _id: id, user: openId })if (!data) {return res.json({ code: 404, message: "未找到匹配的书籍" });}return res.json({ code: 200, message: "查询成功", data });} catch (err) {console.error("Error creating book:", err);return res.json({ code: 500, message: "查询失败", error: err.message });}
}
// 删除ID
exports.delBook = async (req, res) => {let { id } = req.params;let { openId } = req.usertry {const result = await BookModel.deleteOne({ _id: id, user: openId })if (result.deletedCount === 1) {// 成功删除return res.json({ code: 200, message: "删除成功", data: {} });} else {// 没有匹配的文档return res.json({ code: 404, message: "未找到匹配的文档" });}} catch (err) {console.error("Error deleting book:", err);return res.json({ code: 500, message: "删除失败", error: err.message });}
}
声明文档
// 导入 mongoose
const mongoose = require('mongoose')// 创建文档的结构对象
// 设置集合中 文档的属性 以及类型值
let UserSchema = new mongoose.Schema({openId: String, // 添加 openId 字段token: String,id: String,
});
// 创建模型对象 : mongoose 会使用集合的复数去创建集合
let UserModel = mongoose.model("users", UserSchema);// 暴露模型对象
module.exports = UserModel-------------------------------------------------------书籍相关----------------------------------
// 导入 mongoose
const mongoose = require('mongoose')// 5. 创建文档的结构对象
// 设置集合中 文档的属性 以及类型值
let BookSchema = new mongoose.Schema({name: {type: String,required: true, // 必填unique: true // 独一无二 新集合才可以},author: {type: String,default: '匿名' // 默认值},gender: {type: String,enum: ['男', '女'] // 枚举 必须是里面的内容 },price: Number,is_hot: Boolean,user: {type: String, // 或者其他与用户标识匹配的类型required: true},// tag: Array,// pub_time: Date,
});
// 6.创建模型对象 : mongoose 会使用集合的复数去创建集合
let BookModel = mongoose.model("books", BookSchema);// 暴露模型对象
module.exports = BookModel
效果图


相关文章:
nodeJs+jwt实现小程序tonken鉴权
nodeJsjwt实现小程序tonken鉴权 自我记录 config\config.js // 配置文件 module.exports {DBHOST: 127.0.0.1,DBPORT: 27017,DBNAME: test,secret: xxxxx,// 小程序的appSecretAppID: xxxxx,// 小程序的appId }token中间件 middlewares\checkTokenMiddleware.js //导入 jwt…...
更新andriod studio版本,项目编译报could not find org.junit.jupiter:junit-jupiter
原本使用Android Studio 版本是4.1.1,现更新为 点击build -》 build bundle -》build apk,项目报 Could not determine the dependencies of task :app:compileDebugUnitTestJavaWithJavac. > Could not resolve all task dependencies for configur…...
【慕伏白教程】 Linux 深度学习服务器配置指北
文章目录 镜像烧录系统安装系统配置常用包安装 镜像烧录 下载 Ubuntu 镜像 Ubuntu 桌面版 下载烧录工具 balenaEtcher 准备至少 8G 的 空白U盘 开始烧录 系统安装 开机进入BIOS,修改U盘为第一启动 选择 Try or Install Ubuntu 往下拉,选择 中文&a…...
学习windows系统让python脚本在后台运行的方法
学习windows系统让python脚本在后台运行的方法 windows 后台运行并输出日志文件windows 前台运行并输出日志文件 windows 后台运行并输出日志文件 命令: python qipa250.py >> qipa250_logs.log 2>&1 &窗口关闭后程序也就关闭了 windows 前台运…...
华为OD机试 - 第k个排列 - 全排列递归(Java 2023 B卷 100分)
目录 专栏导读一、题目描述二、输入描述三、输出描述四、解题思路五、Java算法源码六、效果展示1、输入2、输出3、说明 华为OD机试 2023B卷题库疯狂收录中,刷题点这里 专栏导读 本专栏收录于《华为OD机试(JAVA)真题(A卷B卷&#…...
流媒体播放器EasyPlayer.js无法播放H.265的情况是什么原因?该如何解决?
H5无插件流媒体播放器EasyPlayer属于一款高效、精炼、稳定且免费的流媒体播放器,可支持多种流媒体协议播放,可支持H.264与H.265编码格式,性能稳定、播放流畅,能支持WebSocket-FLV、HTTP-FLV,HLS(m3u8&#…...
负载均衡器监控
什么是负载均衡器 负载均衡建立在现有网络结构之上,它提供了一种廉价有效透明的方法扩展网络设备和服务器的带宽、增加吞吐量、加强网络数据处理能力、提高网络的灵活性和可用性。其意思就是分摊到多个操作单元上进行执行,例如Web服务器、FTP服务器、企…...
【计算机视觉】2.图像特征提取
图像特征提取 一、颜色特征量化颜色直方图聚类颜色直方图 二、边缘特征边缘边缘定义边缘提取边缘精细 三、特征点的特征描述子Harris角点FAST角点斑点SIFTHaar-like特征SURFORBLBPGabor 一、颜色特征 量化颜色直方图 HSV空间 优势:计算高效 劣势:量化问…...
华为存储培训
01 存储前沿技术和发展趋势 狭义的存储定义 CD、DVD、ZIP、磁带、硬盘等 广义的存储定义 存储硬件系统(磁盘阵列,控制器,磁盘柜,磁带库等) 存储软件(备份软件;管理软件,快照&…...
I帧、P帧,B帧,GOP
doGetNextFrame() 在Live555库的FramedSource类中,数据帧的获取位置由doGetNextFrame()函数来设置。这个函数是一个虚函数,子类可以重写它以实现特定类型的数据帧获取逻辑。 在FramedSource的子类中,你可以重写doGetNextFrame()函数&#x…...
Apache DolphinScheduler在中国信通院“2023 OSCAR开源尖峰案例”评选中荣获「尖峰开源项目奖」!
在近日由中国信息通信研究院(以下简称“中国信通院”)和中国通信标准化协会联合主办的“2023 OSCAR 开源产业大会”上,主办方公布了 2023 年“OSCAR 开源尖峰案例”评选结果,包括“开源人物”“开源项目”“开源社区”“开源企业”…...
Java Lambda 表达式
💗wei_shuo的个人主页 💫wei_shuo的学习社区 🌐Hello World ! Java Lambda 表达式 Java Lambda 表达式是 Java 8 引入的一种函数式编程特性,它是一种轻量级的匿名函数,允许我们将函数作为方法的参数进行传递…...
数据结构--插入排序
目录 插入排序 算法实现 算法效率分析 插入排序的优化-折半插入排序 最终的结果:(方式) 优化-折半查找的代码实现 回顾 插入排序 算法实现 算法效率分析 空间复杂度和问题规模无关 插入排序的优化-折半插入排序 之前的元素有序&am…...
服务器搭建(TCP套接字)-epoll版(服务端)
epoll 是一种在 Linux 系统上用于高效事件驱动编程的 I/O 多路复用机制。它相比于传统的 select 和 poll 函数具有更好的性能和扩展性。 epoll 的主要特点和原理: 1、事件驱动:epoll 是基于事件驱动的模型,它通过监听事件来触发相应的回调函…...
第一章:最新版零基础学习 PYTHON 教程(第十八节 - Python 表达式语句–Python 中的中断、继续和传递)
在 Python 中使用循环可以高效地自动执行和重复任务。但有时,可能会出现您想要完全退出循环、跳过迭代或忽略该条件的情况。这些可以通过循环控制语句来完成。循环控制语句改变其正常顺序的执行。当执行离开作用域时,在该作用域中创建的所有自动对象都将被销毁。Python支持以…...
Spring Cloud Alibaba Ribbon负载均衡器
文章目录 Ribbon 负载均衡器环境搭建1.依赖2.配置3.修改其默认的负载均衡策略3.1 验证 4.创建自定义的Rule4.1 MyRule()4.2 在配置config类中配置 5.饥饿加载6.我只想访问不想被别的访问 Ribbon 负载均衡器 背景 Ribbon 是一个用于客户端负载均衡的开源…...
ardupilot开发 ---传感器驱动,外设驱动篇
ardupilot支持不同厂商的传感器,如雷达,声呐,激光,相机等; 支持的通信协议 I2C, SPI, UART (aka Serial) CANBUS 驱动程序的前后台分离 ardupilot中传感器驱动的重要结构是前后分离; Library库调用前端…...
二叉树的存储
目录 1.使用孩子表示法创建二叉树 2.二叉树的遍历 2.1前中后序遍历 2.2 前中后序遍历的选择题 2.3实现前中后序遍历 2.3.1前序遍历 2.3.2中序遍历 2.3.3后序遍历 3.二叉树的基本操作 3.1获取叶子节点的个数 3.2获取树中节点的个数 3.3获取第K层节点的个数 3.4获取…...
List 去重的几种方法
🔔HashSet去重 import java.util.HashSet;HashSet<Integer> set new HashSet<>(); set.add(1); set.add(2); set.add(2); System.out.println(set); // [1, 2]🔔TreeSet去重 import java.util.TreeSet;TreeSet<Integer> set new T…...
UNet网络制作
UNet网络制作 代码参考UNet数据集制作及代码实现_哔哩哔哩_bilibili,根据该UP主的代码,加上我的个人整理和理解。(这个UP主的代码感觉很好,很规范 UNet网络由三部分组成:卷积块,下采样层,上采样…...
基于大模型的 UI 自动化系统
基于大模型的 UI 自动化系统 下面是一个完整的 Python 系统,利用大模型实现智能 UI 自动化,结合计算机视觉和自然语言处理技术,实现"看屏操作"的能力。 系统架构设计 #mermaid-svg-2gn2GRvh5WCP2ktF {font-family:"trebuchet ms",verdana,arial,sans-…...
进程地址空间(比特课总结)
一、进程地址空间 1. 环境变量 1 )⽤户级环境变量与系统级环境变量 全局属性:环境变量具有全局属性,会被⼦进程继承。例如当bash启动⼦进程时,环 境变量会⾃动传递给⼦进程。 本地变量限制:本地变量只在当前进程(ba…...
mongodb源码分析session执行handleRequest命令find过程
mongo/transport/service_state_machine.cpp已经分析startSession创建ASIOSession过程,并且验证connection是否超过限制ASIOSession和connection是循环接受客户端命令,把数据流转换成Message,状态转变流程是:State::Created 》 St…...
Psychopy音频的使用
Psychopy音频的使用 本文主要解决以下问题: 指定音频引擎与设备;播放音频文件 本文所使用的环境: Python3.10 numpy2.2.6 psychopy2025.1.1 psychtoolbox3.0.19.14 一、音频配置 Psychopy文档链接为Sound - for audio playback — Psy…...
【HTTP三个基础问题】
面试官您好!HTTP是超文本传输协议,是互联网上客户端和服务器之间传输超文本数据(比如文字、图片、音频、视频等)的核心协议,当前互联网应用最广泛的版本是HTTP1.1,它基于经典的C/S模型,也就是客…...
优选算法第十二讲:队列 + 宽搜 优先级队列
优选算法第十二讲:队列 宽搜 && 优先级队列 1.N叉树的层序遍历2.二叉树的锯齿型层序遍历3.二叉树最大宽度4.在每个树行中找最大值5.优先级队列 -- 最后一块石头的重量6.数据流中的第K大元素7.前K个高频单词8.数据流的中位数 1.N叉树的层序遍历 2.二叉树的锯…...
Redis:现代应用开发的高效内存数据存储利器
一、Redis的起源与发展 Redis最初由意大利程序员Salvatore Sanfilippo在2009年开发,其初衷是为了满足他自己的一个项目需求,即需要一个高性能的键值存储系统来解决传统数据库在高并发场景下的性能瓶颈。随着项目的开源,Redis凭借其简单易用、…...
c++第七天 继承与派生2
这一篇文章主要内容是 派生类构造函数与析构函数 在派生类中重写基类成员 以及多继承 第一部分:派生类构造函数与析构函数 当创建一个派生类对象时,基类成员是如何初始化的? 1.当派生类对象创建的时候,基类成员的初始化顺序 …...
ubuntu22.04有线网络无法连接,图标也没了
今天突然无法有线网络无法连接任何设备,并且图标都没了 错误案例 往上一顿搜索,试了很多博客都不行,比如 Ubuntu22.04右上角网络图标消失 最后解决的办法 下载网卡驱动,重新安装 操作步骤 查看自己网卡的型号 lspci | gre…...
数据库——redis
一、Redis 介绍 1. 概述 Redis(Remote Dictionary Server)是一个开源的、高性能的内存键值数据库系统,具有以下核心特点: 内存存储架构:数据主要存储在内存中,提供微秒级的读写响应 多数据结构支持&…...
