nodeJs+jwt实现小程序tonken鉴权

news2024/11/26 17:51:56

nodeJs+jwt实现小程序tonken鉴权

自我记录
config\config.js

// 配置文件
module.exports = {
    DBHOST: '127.0.0.1',
    DBPORT: '27017',
    DBNAME: 'test',
    secret: 'xxxxx',// 小程序的appSecret
    AppID: '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
    })
  }
  //校验 token
  const 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 });
        // 判断 data
        if (!data) {
            return res.json({
                code: 400,
                msg: '用户名或密码错误',
                data: null
            });
        }
        // 创建当前用户的 token
        const token = await getToken(data.openId, data.id)

        // 响应 token
        res.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 {
        // 销毁 token
        await 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.user
    try {
        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.user
    try {
        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

效果图
在这里插入图片描述
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1042610.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

密码学【第一节:密码学概述】

前言 在区块链的整个体系中大量使用了密码学算法&#xff0c;比如用于 PoW 的哈希算法&#xff0c;用于完整性验证的 Merkle Tree&#xff0c;用于交易签名与验证的数字签名算法&#xff0c;用于隐私保护的零知识证明等等。 可以说密码学是保证区块链安全的基石&#xff0c;而区…

AIRIOT亮相IOTE2023深圳物联网展,产品创新力再获“IOTE金奖”

9月20-22日&#xff0c;IOTE 2023第二十届深圳国际物联网展在深圳国际会展中心&#xff08;宝安&#xff09;圆满落幕。作为物联网领域年度最重要的行业盛会之一&#xff0c;本届展会以“IoT构建数字经济底座”为主题&#xff0c;汇聚全球来自工业、物流、基建、智慧城市、智慧…

java项目之旅游景点线路网站(ssm源码+文档)

项目简介 旅游景点线路网站实现了以下功能&#xff1a; 管理员&#xff1a;个人中心、会员管理、景点分类管理、旅游景点管理、旅游线路管理、系统管理。会员&#xff1a;个人中心、旅游景点管理、旅游线路管理、我的收藏管理等操作。 &#x1f495;&#x1f495;作者&#x…

OSPF特殊区域NSSA和Totally NSSA详解及配置

本文主要介绍OSPF中的另外一种特殊区域&#xff1a;NSSA以及Totally NSSA区域。 如下图&#xff1a; 当AR1和AR3同时连接到某一外部网络&#xff0c;AR3引入外部路由到OSPF域&#xff0c;AR1所在的Area 1为减小LSDB规模被设置为Stub或Totally Stub区域。这时&#xff0c;由于…

滴答定时器SysTick和os_cpu_a.asm(UCOS的移植)

一、滴答定时器SysTick 滴答定时器是一个 24 位的倒计数定时器&#xff0c;当计到 0 时&#xff0c;将从 RELOAD 寄存器中自动重装载定时器初值&#xff0c;只要不把它在 SysTick 控制以及状态寄存器中的使能位清零&#xff0c;就将永久不息。SysTick 的最大使命&#xff0c;就…

Windows Server 2022 安全功能重大更新

这篇文将介绍 Windows Server 2022 中的一些新增的安全功能&#xff0c;在 Windows Server 2019 的强大基础之上引入了许多创新功能。 文章目录 一、传输&#xff1a;Windows Server 2022 上默认启用 HTTPS 和 TLS 1.3二、安全 DNS&#xff1a;通过基于 HTTPS 的 DNS 实现 DNS…

基于SpringBoot的CSGO赛事管理系统springboot20

大家好✌&#xff01;我是CZ淡陌。一名专注以理论为基础实战为主的技术博主&#xff0c;将再这里为大家分享优质的实战项目&#xff0c;本人在Java毕业设计领域有多年的经验&#xff0c;陆续会更新更多优质的Java实战项目&#xff0c;希望你能有所收获&#xff0c;少走一些弯路…

功率放大器是不是越大越好用

功率放大器的大小是个相对的概念&#xff0c;没有绝对的“越大越好用”的说法。不同的应用场景和需求需要不同大小的功率放大器&#xff0c;因此选择适合的功率放大器是很重要的。 我们需要明确功率放大器的作用是对信号进行放大&#xff0c;使其能够驱动负载。因此&#xff0c…

c++均值滤波:cv::blur

c均值滤波&#xff1a;cv::blur cv::blur 是 OpenCV 中用于进行均值滤波的函数。均值滤波是一种基本的图像平滑处理方法&#xff0c;它用于减小图像中的噪声&#xff0c;平滑图像并模糊细节。 以下是 cv::blur 的一般形式&#xff1a; void cv::blur(cv::InputArray src, cv…

百分比组件

//组件 <template><div :class"className" :style"{ height: height, width: width }" style"overflow: hidden;" /> </template><script> export default {props: {className: {type: String,default: "chart&quo…

springboot+vue+java天气预报管理系统1439

本天气管理系统使用了开源框架SpringBoot开发实现了天气管理系统&#xff0c;并且使用了开发工具idea和数据库MySQL。在开发实现天气管理系统之前&#xff0c;需要对系统进行需求分析和调研&#xff0c;从而分析出天气管理系统需要具备什么样的功能&#xff0c;设计出对应的总体…

U盘数据防泄密软件(U盘防泄密加密软件都有哪些?)

随着科技的发展&#xff0c;U盘已经成为了我们日常生活中不可或缺的一部分。然而&#xff0c;U盘的便捷性也带来了安全隐患。为了保护您的数据安全&#xff0c;U盘防泄密加密系统应运而生。本文将从三个方面为您介绍U盘防泄密加密系统是什么、有哪些以及能做什么。 一、U盘防泄…

DataX: Ⅱ

序言 这里使用的是master分支,因为官网上并没有release分支,所以先用master分支吧,可能会有问题cuiyaonan2000163.com 参考资料: https://github.com/alibaba/DataXhttps://github.com/alibaba/DataX/blob/master/introduction.md --插件说明文档 源码打包 首先下载 Git…

二、VXLAN BGP EVPN基本原理

VXLAN BGP EVPN基本原理 1、BGP EVPN2、BGP EVPN路由2.1、Type2路由——MAC/IP路由2.2、Type3路由——Inclusive Multicast路由2.3、Type5路由——Inclusive Multicast路由 ————————————————————————————————————————————————…

static const char* 和const char*有报错,发生访问冲突

const char *srcfilere aByteArray.data(); 当重复某一操作时&#xff1a;有报错&#xff0c;发生访问冲突 const char *srcfilere aByteArray.data(); 即可解决访问冲突问题。 困扰了至少一天吧 应该是static的问题&#xff0c;吃了基础不好的亏。

CMD命令终端快捷键学习

很多环境需要安装并且指定环境变量才可用终端访问 比如一些数据库、一些环境、例如&#xff1a;nodejs Oracle、mysql 在一个文件夹按住shift鼠标右键可以快速在当前目录运行终端&#xff01;免去cd 目录的烦恼 快捷键 当你学习和使用命令终端&#xff08;如 Windows 的 CMD&…

如何让IPad Pro变成你的生产力工具?在IPad上用Vscode写代码搞开发

文章目录 前言1. 本地环境配置2. 内网穿透2.1 安装cpolar内网穿透(支持一键自动安装脚本)2.2 创建HTTP隧道 3. 测试远程访问4. 配置固定二级子域名4.1 保留二级子域名4.2 配置二级子域名 5. 测试使用固定二级子域名远程访问6. ipad pro通过软件远程vscode6.1 创建TCP隧道 7. ip…

如何用芯片ate测试设备测试芯片过压保护和过流保护?

过压保护和过流保护是指被保护的产品或电路在电压/电流超过正常运行的最大值时&#xff0c;使输入断开或内部电压/电流降低的一种保护方式。过压保护和过流保护是为了防止电路中电压/电流过大从而损坏产品&#xff0c;因此过压/过流保护电压值和电流值也是电子测试中不可或缺的…

树莓派(Linux系统通用)交叉编译(环境搭建、简单使用)

概念 交叉编译是指在一台计算机上编译运行在另一台计算机上的程序。&#xff08;编译是指&#xff0c;在一个平台上生成在该平台上的可执行程序&#xff09;通常情况下&#xff0c;编译器和目标平台的架构是不同的&#xff0c;例如&#xff0c;在一台x86平台上编译运行在ARM平…