三、node,mongoose实现用户登录token生成、鉴权

用户Schema和密码加密

        首先,我们使用Mongoose定义用户数据模型。这里包含用户名(username)和密码(password),并且在密码字段上设置了一个预保存钩子(pre-save hook),用于在存储到数据库前对其进行bcrypt加密,使用bcryptjs工具。

const mongoose = require('mongoose');
const bcrypt = require('bcryptjs');

// 定义用户Schema
const userSchema = new mongoose.Schema({
  name: { type: String, required: true },
  email: { type: String, unique: true, required: true },
  password: { type: String, required: true },
  // 其他字段...
});

// 预保存钩子:在保存用户前对密码进行bcrypt哈希处理
userSchema.pre('save', async function (next) {
  if (!this.isModified('password')) return next();
  this.password = await bcrypt.hash(this.password, 10); // 加密强度为10的bcrypt算法
  next();
});

// 创建并注册User Model
const User = mongoose.model('User', userSchema);
用户登录功能

        创建一个处理用户登录请求的API端点,验证email和密码是否匹配,并在成功时生成JWT Token,如果用户不存在则创建一个新用户。

 文件:routes/user.js

// usersRoutes.js
const express = require("express");
const bcrypt = require("bcryptjs");
const jwt = require("jsonwebtoken");
const secret = 'mySuperSecretKeyForJwtSigning';
const { User } = require("../model/main"); // 确保路径正确指向db.js文件

const router = express.Router();

// 定义登录路由
router.post("/login", async (req, res) => {
  try {
    const { email, password, name } = req.body;
    // 先尝试查询数据库获取对应用户名的用户
    let user = await User.findOne({ email });
    if (!user) {
      // 如果用户不存在,则创建新用户并保存到数据库
      user = new User({ email, password, name });
      await user.save();
    } else {
      // 对于已存在的用户,验证密码是否匹配
      if (!await bcrypt.compare(password, user.password)) {
        return res.status(401).json({ error: 'Invalid credentials' });
      }
    }
    // 密码正确或新用户已创建,生成Token
    const token = jwt.sign({ userId: user._id }, secret, { expiresIn: "1h" }); // 设置过期时间为1小时
    // 将Token和其他用户信息返回给客户端
    res.json({ token, name: user.name || null, id: user._id, email: user.email });
  } catch (error) {
    console.error(error);
    res.status(500).json({ error: "Server error" });
  }
});

// 查询单个用户或所有用户接口
router.get("/:id?", async (req, res) => {
  try {
    if (req.params.id) {
      const userId = req.params.id;
      const user = await User.findById(userId);
      if (!user) {
        return res.status(404).json({ message: "User not found." });
      }
      res.json(user);
    } else {
      const users = await User.find();
      res.json(users);
    }
  } catch (error) {
    console.error("Error fetching user(s):", error);
    res
      .status(500)
      .json({ error: "An error occurred while fetching the user(s)." });
  }
});

module.exports = router;
JWT Token生成说明

        这里利用jsonwebtoken库根据用户ID生成一个签名的Token,这个Token内包含了用户的唯一标识符userId。设定一定的过期时间以提高安全性。

const jwt = require('jsonwebtoken');
const secret = 'mySuperSecretKeyForJwtSigning' // process.env.JWT_SECRET 这个secret应从环境变量中获取,确保安全

// 假设上述login函数内部
const token = jwt.sign({ userId: user._id }, secret, { expiresIn: '1h' }); // 过期时间为1小时
JWT鉴权中间件

        创建一个中间件,该中间件会在每次保护路由被访问时执行。其作用是从请求头中提取Token,并解码验证Token的有效性。如果有效,则将解码后的用户信息附加到请求对象上以便后续操作。

文件:auth.js

const jwt = require("jsonwebtoken");
const secret = "mySuperSecretKeyForJwtSigning";

const authMiddleware = (req, res, next) => {
  const noAuthPaths = ["/api/users/login"];
  if (noAuthPaths.some((path) => req.path.startsWith(path))) {
    return next(); // 路径在白名单内,直接进入下一个中间件或路由处理函数
  }
  const authorizationHeader = req.headers["authorization"];
  // 检查请求头中是否存在Authorization头,并从中提取出Bearer后面的Token部分
  if (!authorizationHeader || !authorizationHeader.startsWith("Bearer ")) {
    return res.status(401).json({ error: "Unauthorized" });
  }
  const token = authorizationHeader.split(" ")[1];
  try {
    // 解码并验证Token
    const decoded = jwt.verify(token, secret);
    // 将解码得到的用户信息添加到请求对象上
    req.user = decoded;
    next();
  } catch (err) {
    return res.status(401).json({ error: "Unauthorized" });
  }
};

module.exports = authMiddleware;
在应用中全局启用鉴权中间件 
const authMiddleware = require('./auth');
app.use(authMiddleware)

server.js文件完整代码 

// server.js
const express = require('express');
const bodyParser = require('body-parser');
const cors = require('cors');
const { connect } = require('./db'); // 确保路径正确指向db.js文件
const authMiddleware = require('./auth');

const app = express();
app.use(cors());
app.use(bodyParser.json());
app.use(authMiddleware)

// 在服务器启动前先连接数据库
async function startServer() {
  try {
    await connect();
    console.log('Connected to MongoDB');
    // 挂载用户路由到 /api/users
    const usersRoutes = require('./routes/user');
    app.use('/api/users', usersRoutes);
    // 启动服务器
    const PORT = process.env.PORT || 3000;
    app.listen(PORT, () => {
      console.log(`Server is running on port ${PORT}`);
    });
  } catch (error) {
    console.error('Error connecting to MongoDB:', error);
  }
}

startServer();
前端调用展示:

        

        以上代码展示了如何在Node.js与Mongoose配合下实现用户登录及基于JWT的Token鉴权机制的基本流程。实际项目中还应考虑更多细节,例如异常处理、Token刷新策略、Token黑名单管理等。 

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

用ASM HEMT模型提取GaN器件的参数

标题:Physics-Based Multi-Bias RF Large-Signal GaNHEMT Modeling and Parameter Extraction Flow (JEDS 17年) 模型描述 该模型的核心是对表面势(ψ)及其随施加的栅极电压(Vg)和漏极电压(Vd&#xff09…

1分钟内生成美妙歌曲:Suno AI的音乐魔法

1分钟内生成美妙歌曲:Suno AI的音乐魔法 Suno AI是一款人工智能工具,让创作者能够生成超现实的音乐、语音和音效,可以根据用户的指令生成音乐、语音和其他音频内容。它可以帮助创作者快速生成高质量的音乐作品,并且可以根据不同的…

【Qt无门槛入门】信号以及信号机制及其常用控件(1)

信号与信号槽 信号源:由哪个控件发出的信号。 信号的类型:用户进行不同的操作,就可能出发不同的信号。 信号处理的方式:槽(slot)某个对象接收到这个信号之后,就会做一些相关的处理动作。但是Qt对象不会无故…

02-Linux入门

说明:01-VMware还没有写笔记,因为这个VMware我很久之前就装好了,先给自己挖个坑,回头有空了补一下01-VMware(包括安装、使用、xshell的操作等 说明)的笔记吧。 下面关于Linux的笔记是根据黑马的视频所写的&…

Notepad 将多行转换成字符串,合并成一行

notepad 将多行转换成字符串,合并成一行 (1) 快捷键 ctrl H ,选择 【替换】, (2) 【查找目标】,输入 \r\n , 这个正则表达式的含义是 换行回到行首,相当于 windows的 enter 键: \r&#xff…

十分钟搭建本地Linux开发运行环境

十分钟搭建本地开运行环境 linux环境请参考:5分钟搭建本地linux开发环境 环境:宝塔、Jdk、Mysql、Redis 1、宝塔: 官网地址:宝塔官网 yum install -y wget && wget -O install.sh https://download.bt.cn/install/in…

【labVIEW】学习记录

【labVIEW】学习记录 一、简介二、安装及激活三、使用 回到目录 一、简介 labVIEW(Laboratory Virtual Instrument Engineering Workbench)是一款由美国国家仪器公司(National Instruments)开发的可视化编程环境和开发平台。LabV…

scrapy框架核心知识Spider,Middleware,Item Pipeline,scrapy项目创建与启动,Scrapy-redis与分布式

scrapy项目创建与启动 创建项目 在你的工作目录下直接使用命令: scrapy startproject scrapytutorial运行后创建了一个名为scrapytutorial的爬虫工程 创建spider 在爬虫工程文件内,运行以下命令: scrapy genspider quotes创建了名为quotes的爬虫 …

Logistics 逻辑回归概念

1. sigmoid函数 逻辑回归算法的拟合函数,叫做sigmoid函数: 函数图像如下(百度图片搜到的图): sigmoid函数是一个s形曲线,就像是阶跃函数的温和版,阶跃函数在0和1之间是突然的起跳,…

Unity中URP下额外灯角度衰减

文章目录 前言一、额外灯中聚光灯的角度衰减二、AngleAttenuation函数的传入参数1、参数:spotDirection.xyz2、_AdditionalLightsSpotDir3、参数:lightDirection4、参数:distanceAndSpotAttenuation.zw5、_AdditionalLightsAttenuation 三、A…

【Git】windows系统安装git教程和配置

一、何为Git Git(读音为/gɪt/)是一个开源的分布式版本控制系统,可以有效、高速地处理从很小到非常大的项目版本管理。 二、git安装包 有2种版本,Git for Windows Setup和Git for Windows Portable(便携版)两个版本都可以。 三、Git for Windows Por…

【服务器】宝塔面板的使用手册

目录 🌷概述 🌼1. 绑定域名 🌼2. 添加端口 🌼3. 安装docker配置docker​​​​​​​ 🌼4. 软件商店 🌼5. 首页 🌷概述 宝塔面板的安装教程:【服务器】安装宝塔面板 &#x1f…

[BJDCTF2020]The mystery of ip

hint 猜测ip和XFF有关 加一个XFF 下面这一步是看了wp出来的:存在ssti 这里尝试用jinja的注入方法,页面回显了是php的smarty框架 查了一下smarty的注入方法,发现可以直接执行php命令 在根目录找到flag

SpringBoot深入解析:掌握自动装配机制及其定制化原理

推荐一款我一直在用的ChatGPT4.0国内站点,每日有免费使用额度,支持PC、APP、VScode插件同步使用 SpringBoot篇:SpringBoot的自动装配原理 SpringBoot是一个旨在简化Spring应用初始搭建以及开发过程的框架。它利用了Spring框架的依赖注入特性…

(免费分享)基于springboot,vue疗养中心管理系统

前端:vueelementUI 技术:springbootmybatisredis 数据库:mysql 功能:系统管理、信息管理、膳食管理、护理管理、床位管理、后勤管理、费用管理等 获取完整源码: 大家点赞、收藏、关注、评论啦 、查看 👇…

Java实现木马文件检测系统 JAVA+Vue+SpringBoot+MySQL

目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块2.1 数据中心模块2.2 木马分类模块2.3 木马软件模块2.4 安全资讯模块2.5 脆弱点模块2.6 软件检测模块 三、系统设计3.1 用例设计3.2 数据库设计3.2.1 木马分类表3.2.2 木马软件表3.2.3 资讯表3.2.4 脆弱点表3.2.5 软件检测表…

「 典型安全漏洞系列 」07.OS命令注入详解

引言:什么是操作系统命令注入,如何防御和利用漏洞? 1. 简介 操作系统命令注入(OS command injection)是一种Web安全漏洞,允许攻击者在运行应用程序的服务器上执行任意操作系统(OS)命…

静态分析Golang语言生成函数调用关系的利器——go-callvis

目录 升级go删除旧版本安装新版本配置环境变量载入环境修改当前环境修改之后进入的环境 分析安装go-callvis分析其他包总结 导出文件总结 清晰主体脉络总结 其他 参考资料 不同于之前分析C语言项目的工具,go-callvis还是很方便使用。只要把两项工作做好就能顺利的使…

条件变量、线程池以及线程的GDB调试学习笔记

目录 一、条件变量 二、线程池概念和实现 三、线程的GDB调试 一、条件变量 应用场景:生产者消费者问题,是线程同步的一种手段。 必要性:为了实现等待某个资源,让线程休眠,提高运行效率 使用步骤: 初始…

SpringMVC 的请求流程(高频面试题)

文章目录 SpringMVC是什么,好处请求流程 SpringMVC 是什么,好处 Spring MVC 是Spring上最重要的框架。它是Web 框架,按照MVC 的模式,实现代码的解耦。Model 业务层、View 视图层、Controller 控制层。 将view层的请求数据在con…