【Node.js从基础到高级运用】十二、身份验证与授权:JWT
身份验证与授权是现代Web应用中不可或缺的部分。了解如何在Node.js应用中实施这些机制,将使你能够构建更安全、更可靠的应用程序。本文将引导你通过使用
JWT实现用户注册、登录和权限控制的过程。
JWT(Json Web Token)
JWT是一种用于双方之间安全地传输信息的简洁的、URL安全的表示声明的方法。它由三部分组成:头部(Header)、载荷(Payload)、签名(Signature)。
JWT的实现步骤
安装依赖
首先,安装JWT相关的npm包:
npm install jsonwebtoken --save
创建JWT
在用户登录成功后,你需要创建一个token发送给用户:
const jwt = require('jsonwebtoken');const user = { id: user.id }; // 用户的唯一标识
const secret = 'your_secret_key'; // 保持安全的秘钥
const token = jwt.sign(user, secret, { expiresIn: '1h' }); // 有效期1小时
验证JWT
创建一个中间件来验证每次请求的JWT:
function authenticateToken(req, res, next) {const authHeader = req.headers['authorization'];// 从请求头中获取'authorization'字段const token = authHeader && authHeader.split(' ')[1];if (token == null) return res.sendStatus(401);// 如果没有token,则返回401jwt.verify(token, 'your_secret_key', (err, user) => {if (err) return res.sendStatus(403);// 如果token验证失败,则返回403req.user = user;next();});
}
权限控制
使用前面创建的authenticateToken中间件来控制访问特定路由的权限:
app.get('/protected', authenticateToken, (req, res) => {res.json({ message: 'This is protected' });// 这个路由现在受到保护,只有带有有效JWT的请求才能访问
});
结合Express + MongoDB + JWT 示例
准备工作
安装必要的npm包
npm install express mongoose@4.4.0 jsonwebtoken bcryptjs body-parser --save
这些包包括Express框架、Mongoose(MongoDB的ODM)、jsonwebtoken(用于JWT操作)、bcryptjs(用于密码加密)和body-parser(用于解析请求体)。
启动MongoDB服务
确保MongoDB服务在本地运行或者你有一个MongoDB Atlas云服务的实例。
mongo
开始
设置Express应用
const express = require('express'); // 引入express模块
const bodyParser = require('body-parser'); // 引入body-parser模块用于解析请求体
const mongoose = require('mongoose'); // 引入mongoose模块连接MongoDB
const { register, login, authenticateToken } = require('./controllers/authController'); // 引入控制器const app = express(); // 创建express应用
const PORT = process.env.PORT || 3000; // 定义端口号app.use(bodyParser.json()); // 使用body-parser中间件解析JSON格式请求体
// 构建MongoDB连接的URL
const url = 'mongodb://localhost:27017/mydb'; // 这里将地址和数据库名拼接在了一起
// 连接到MongoDB数据库
//mongoose.connect方法用于初始化数据库连接。
//它接受两个参数:
//第一个参数是MongoDB的连接字符串,
//第二个参数是一个选项对象,
//这里使用了useNewUrlParser和useUnifiedTopology选项
//以使用新的URL解析器和驱动引擎,这两个选项有助于避免一些常见的连接警告。
mongoose.connect(url, { useNewUrlParser: true, useUnifiedTopology: true }).then(() => console.log('MongoDB connected')) // 连接成功后打印消息.catch(err => console.log(err)); // 连接失败打印错误信息// 注册和登录路由
app.post('/register', register);
app.post('/login', login);// 受保护的路由示例,使用authenticateToken中间件保护
app.get('/protected', authenticateToken, (req, res) => {res.json({ message: 'This is protected' }); // 受保护的资源
});// 启动服务器
app.listen(PORT, () => {console.log(`Server is running on port ${PORT}`);
});
创建User模型
在models/User.js中:
const mongoose = require('mongoose'); // 引入mongoose模块// 定义用户模型的schema
const userSchema = new mongoose.Schema({username: { type: String, required: true, unique: true }, // 用户名,必填,唯一password: { type: String, required: true } // 密码,必填
});// 导出模型
module.exports = mongoose.model('User', userSchema);
实现注册与登录逻辑
在controllers/authController.js中:
const bcrypt = require('bcryptjs'); // 引入bcryptjs用于密码加密
const jwt = require('jsonwebtoken'); // 引入jsonwebtoken用于生成JWT
const User = require('../models/User'); // 引入User模型// 注册逻辑
exports.register = async (req, res) => {const { username, password } = req.body; // 从请求体获取用户名和密码const hashedPassword = await bcrypt.hash(password, 10); // 对密码进行加密try {// 创建新用户并保存到数据库const newUser = await User.create({ username, password: hashedPassword });res.status(201).json(newUser); // 发送201响应和新用户信息} catch (error) {res.status(500).json({ error: error.message }); // 发送500响应和错误信息}
};// 登录逻辑
exports.login = async (req, res) => {const { username, password } = req.body; // 从请求体获取用户名和密码const user = await User.findOne({ username }); // 查找用户// 如果用户不存在或密码错误if (!user || !(await bcrypt.compare(password, user.password))) {return res.status(401).send('Invalid credentials'); // 发送401响应}// 生成JWTconst token = jwt.sign({ userId: user._id }, 'your_secret_key', { expiresIn: '1h' });res.json({ token }); // 发送包含JWT的响应
};// JWT验证中间件
exports.authenticateToken = (req, res, next) => {const authHeader = req.headers['authorization']; // 获取请求头中的authorization字段const token = authHeader && authHeader.split(' ')[1]; // 提取tokenif (!token) return res.sendStatus(401); // 如果没有token,发送401响应// 验证tokenjwt.verify(token, 'your_secret_key', (err, decoded) => {if (err) return res.sendStatus(403); // 如果验证失败,发送403响应req.userId = decoded.userId; // 将解码的用户ID添加到请求对象next(); // 调用下一个中间件});
};
测试
- 使用Postman或任何API测试工具,先调用
/register端点注册新用户。 - 使用注册信息调用
/login端点,你会收到一个JWT。 - 尝试访问
/protected端点,把JWT添加到请求头中(通常是Authorization:Bearer <your_token>)。 - 如果一切配置正确,你应该能够访问受保护的路由。
http://localhost:3000/register

http://localhost:3000/login

未加token,访问http://localhost:3000/protected

加token,访问http://localhost:3000/protected

总结
本文介绍了如何在Node.js应用中实现用户身份验证和授权,特别是通过使用Node.js、Express和MongoDB实现JWT基于的身份验证和授权的全面指导,包括注册、登录和访问受保护资源的流程。这为构建安全的Web应用程序奠定了坚实的基础。
相关文章:
【Node.js从基础到高级运用】十二、身份验证与授权:JWT
身份验证与授权是现代Web应用中不可或缺的部分。了解如何在Node.js应用中实施这些机制,将使你能够构建更安全、更可靠的应用程序。本文将引导你通过使用JWT实现用户注册、登录和权限控制的过程。 JWT(Json Web Token) JWT是一种用于双方之间…...
蓝桥杯刷题|01入门真题
[蓝桥杯 2020 省 AB1] 解码 题目描述 小明有一串很长的英文字母,可能包含大写和小写。 在这串字母中,有很多连续的是重复的。小明想了一个办法将这串字母表达得更短:将连续的几个相同字母写成字母 出现次数的形式。 例如,连续…...
Python Django相关解答
问题:什么是django? Django是一个开源的高级web框架,皆在快速开发安全可维护的网站。他鼓励快速开发,并遵循“don’t repeat yourself”DRY原则 Django的MTV架构是什么 Django遵循MTV(模型-模板-试图)架构模式。模型(…...
在Linux/Ubuntu/Debian中使用7z压缩和解压文件
要在 Ubuntu 上使用 7-Zip 创建 7z 存档文件,你可以使用“7z”命令行工具。 操作方法如下: 安装 p7zip: 如果你尚未在 Ubuntu 系统上安装 p7zip(7-Zip 的命令行版本),你可以使用以下命令安装它:…...
设计一些策略和技术来防止恶意爬虫
当涉及到反爬虫时,我们需要设计一些策略和技术来防止恶意爬虫访问我们的网站。以下是一个简单的反爬虫框架示例,供您参考: import requests from bs4 import BeautifulSoup import timeclass AntiScrapingFramework:def __init__(self, targ…...
elasticsearch常见问题:xpack.security.transport.ssl、unknown setting [node.master]
文章目录 引言I 安装elasticsearch1.1 安装Master Node1.2 安装Slave nodeII elasticsearch常见问题2.1 invalid configuration for xpack.security.transport.ssl2.2 server ssl configuration requires a key and certificate2.3 unknown setting [node.master]III Kibana启动…...
LLM(大语言模型)——Springboot集成文心一言、讯飞星火、通义千问、智谱清言
目录 引言 代码完整地址 入参 出参 Controller Service Service实现类 模型Service 入参转换类 文心一言实现类 讯飞星火实现类 通义千问实现类 智谱清言实现类 引言 本文将介绍如何使用Java语言,结合Spring Boot框架,集成国内热门大模型API&am…...
什么是堆?什么是栈?
在计算机科学中,"堆(heap)"和"栈(stack)"是两种用于存储数据的数据结构,它们在内存管理中扮演着不同的角色。 堆(Heap): 动态分配内存:…...
【镜像转存】利用交互式学习平台killercoda转存K8S镜像至Docker私人仓库
文章目录 1. 镜像转存需求2. 注册并登陆 killercoda URL3. 打开playground4. 在线拉取K8S镜像并打上标签5. 推送K8S镜像到Docker私有仓库6. 登陆Docker私有仓库查看 1. 镜像转存需求 因K8S镜像在不开代理的情况下,拉取超时、下载缓慢,导致镜像拉取不下来…...
ov多域名SSL数字证书1200元一年送一月
随着互联网的发展,不论是个人用户还是企事业单位都不止有一个网站,为了保护网站安全,就需要为网站安装SSL证书,而SSL证书中的通配符SSL证书和多域名SSL证书都可以同时保护多个域名站点。其中,多域名SSL证书可以同时保护…...
MySQL 系统变量查看与设置(System Variables Configuration)
MySQL中有大量的系统变量控制服务器的行为,大部分的系统变量是不需要我们调整的,保持默认即可。但为了获得更高的性能和稳定性,有时需要适当对部分变量进行调整,本文总结了MySQL中系统变量的查看与设置方法。 目录 一、变量的类型…...
【Docker】apache 容器化部署
Apache环境标准软件基于Bitnami apache 构建。当前版本为2.4.58 你可以通过轻云UC部署工具直接安装部署,也可以手动按如下文档操作,该项目已经全面开源,可以从如下环境获取 配置文件地址: https://gitee.com/qingplus/qingcloud-platform Q…...
基于element-plus +腾讯云COS实现图片上传
① 首先基于element-plus里面的:http-request"upload"自定义封装事件写一个点击事件之后基于腾讯云的 登录 对象存储控制台 ,创建存储桶。获取存储桶名称和 地域名称登录 访问管理控制台 ,获取您的项目 SecretId 和 SecretKey。在项目中安装 …...
Kafka模拟器产生数据仿真-集成StructuredStreaming做到”毫秒“级实时响应StreamData落地到mysql
这是仿真过程某图: 仿真实战kafka kafka消费sink端和StructuredStreaming集成通信成功 , 数据接收全部接收 数据落地情况: 全部接收到并all存入mysql 下面就简单分享一下StructuredStreaming代码吧 import org.apache.spark.sql.function…...
IDEA如何删除git最新一次远程提交
IDEA如何删除git最新一次远程提交 选择应用 -> Git -> Show History 选择最新提交上一次提交 -> Reset Current Branch to Here… Reset 提示框选择 Hard push到远程分支 -> 选择Force Push 结果验证 (最新分支已被删除)...
什么是单向数据流
单向数据流是一种数据流动的模式,通常用于前端框架(如 React、Vue 等)中。在单向数据流中,数据只能从一个方向流向另一个方向,不会出现数据的双向流动。这种模式有助于简化数据的管理和状态的维护,提高代码…...
Qt 线程池 QThreadPool
一.Qt 线程池 QThreadPool介绍 Qt线程池是一种管理多个线程的并发编程模型,通过使用线程池可以提高性能、控制并发度、提供任务队列和简化线程管理。 在Qt中,线程池的使用主要涉及以下几个步骤: 创建任务类:需要定义一个任务类&am…...
【兔子机器人】实现从初始状态到站立
一、遥想星空up主的方法 由于我有卡位结构,无法做到劈腿,而且底盘也不一样,无法使用此方法 但是其代码思想是可以借鉴的。 参考视频: 【【开源啦!】无刷轮腿平衡机器人】 【精准空降到 01:16】 https://www.bilibili…...
ImportError: cannot import name ‘open_filename‘ from ‘pdfminer.utils‘已搞定
报错内容 ImportError: cannot import name ‘open_filename’ from ‘pdfminer.utils’ 第一步:pip uninstall pdfminer 解决办法 pip3 install pdfminer.six注意不要 pip install pdfminer.six是安装不了的...
一文解决Word中公式插入问题(全免费/latex公式输入/texsWord)
分文不花,搞定你的word公式输入/texsWord完全使用指南 背景 碎碎念:折折腾腾至少装了几个小时,遇到了若干大坑。遇到的问题网上都搜索不到答案!!!就让我来当指路的小火柴吧。 本篇适用于在word中输入la…...
Java 语言特性(面试系列2)
一、SQL 基础 1. 复杂查询 (1)连接查询(JOIN) 内连接(INNER JOIN):返回两表匹配的记录。 SELECT e.name, d.dept_name FROM employees e INNER JOIN departments d ON e.dept_id d.dept_id; 左…...
iOS 26 携众系统重磅更新,但“苹果智能”仍与国行无缘
美国西海岸的夏天,再次被苹果点燃。一年一度的全球开发者大会 WWDC25 如期而至,这不仅是开发者的盛宴,更是全球数亿苹果用户翘首以盼的科技春晚。今年,苹果依旧为我们带来了全家桶式的系统更新,包括 iOS 26、iPadOS 26…...
React Native在HarmonyOS 5.0阅读类应用开发中的实践
一、技术选型背景 随着HarmonyOS 5.0对Web兼容层的增强,React Native作为跨平台框架可通过重新编译ArkTS组件实现85%以上的代码复用率。阅读类应用具有UI复杂度低、数据流清晰的特点。 二、核心实现方案 1. 环境配置 (1)使用React Native…...
五年级数学知识边界总结思考-下册
目录 一、背景二、过程1.观察物体小学五年级下册“观察物体”知识点详解:由来、作用与意义**一、知识点核心内容****二、知识点的由来:从生活实践到数学抽象****三、知识的作用:解决实际问题的工具****四、学习的意义:培养核心素养…...
什么是EULA和DPA
文章目录 EULA(End User License Agreement)DPA(Data Protection Agreement)一、定义与背景二、核心内容三、法律效力与责任四、实际应用与意义 EULA(End User License Agreement) 定义: EULA即…...
Spring Boot+Neo4j知识图谱实战:3步搭建智能关系网络!
一、引言 在数据驱动的背景下,知识图谱凭借其高效的信息组织能力,正逐步成为各行业应用的关键技术。本文聚焦 Spring Boot与Neo4j图数据库的技术结合,探讨知识图谱开发的实现细节,帮助读者掌握该技术栈在实际项目中的落地方法。 …...
全志A40i android7.1 调试信息打印串口由uart0改为uart3
一,概述 1. 目的 将调试信息打印串口由uart0改为uart3。 2. 版本信息 Uboot版本:2014.07; Kernel版本:Linux-3.10; 二,Uboot 1. sys_config.fex改动 使能uart3(TX:PH00 RX:PH01),并让boo…...
C#中的CLR属性、依赖属性与附加属性
CLR属性的主要特征 封装性: 隐藏字段的实现细节 提供对字段的受控访问 访问控制: 可单独设置get/set访问器的可见性 可创建只读或只写属性 计算属性: 可以在getter中执行计算逻辑 不需要直接对应一个字段 验证逻辑: 可以…...
基于IDIG-GAN的小样本电机轴承故障诊断
目录 🔍 核心问题 一、IDIG-GAN模型原理 1. 整体架构 2. 核心创新点 (1) 梯度归一化(Gradient Normalization) (2) 判别器梯度间隙正则化(Discriminator Gradient Gap Regularization) (3) 自注意力机制(Self-Attention) 3. 完整损失函数 二…...
LLMs 系列实操科普(1)
写在前面: 本期内容我们继续 Andrej Karpathy 的《How I use LLMs》讲座内容,原视频时长 ~130 分钟,以实操演示主流的一些 LLMs 的使用,由于涉及到实操,实际上并不适合以文字整理,但还是决定尽量整理一份笔…...
