node中使用jsonwebtoken实现身份认证

news2024/12/25 12:25:32

在现代web应用中,用户身份认证是非常重要且必不可少的一环。而使用Node.jsExpress框架,可以方便地实现用户身份认证。而在这个过程中,jsonwebtoken这个基于JWT协议的模块可以帮助我们实现安全且可靠的身份认证机制,可以让我们轻松地生成、解析和验证JWT。本文主要介绍如何在Node.jsExpress框架中使用jsonwebtoken模块来实现用户身份认证。

一、什么是jwt

jwt介绍:https://restfulapi.cn/jwt

JWTJSON Web Token)是一种基于JSON的开放标准,用于在网络上以安全方式传输声明JWT通常用于身份验证和授权。它是一种可自包含的身份认证机制,由三部分组成头部、载荷和签名JWT的头部和载荷都是使用Base64编码后的JSON字符串,签名是由头部和载荷使用密钥进行哈希计算得到的字符串。JWT可以在客户端和服务器之间传输,并且可以在传输过程中防止数据被篡改。由于它是无状态的,因此可以简化Web应用程序的开发和维护。
在这里插入图片描述

二、jsonwebtoken基本使用

jsonwebtoken是一个Node.js库,用于创建、解码和验证JWT令牌(JSON Web Tokens)。在Web应用中,这些令牌通常用于身份验证和授权

以下是如何在Node.js应用中使用jsonwebtoken基本步骤

1. 安装jsonwebtoken

首先,你需要使用npm或yarn将jsonwebtoken包添加到你的项目中:

npm install jsonwebtoken --save

或者

yarn add jsonwebtoken

2. 导入使用

然后,在你的代码中导入jsonwebtoken:

const jwt = require('jsonwebtoken');

3. 创建token

创建一个令牌:

let token = jwt.sign({ foo: 'bar' }, 'shhhhh');

在上面的代码中,我们使用jwt.sign方法创建了一个新的令牌。
这个方法需要两个参数

  • 一个包含你的payload的对象(这个对象中的数据会被编码到生成的令牌中)比如:userInfo
  • 用来签名令牌的秘密字符串

4. 验证token

验证一个令牌:

jwt.verify(token, 'shhhhh', (err, decoded) => {
  if (err) {
    // 处理错误
  } else {
    // 使用解码后的令牌数据
  }
});

使用jwt.verify方法可以解码并验证一个令牌。

该方法需要三个参数

  • 解码的令牌
  • 用于签名的相同的秘密字符串
  • 操作完成时被调用的回调函数

注意

  • 所有的令牌都应该只通过HTTPS发送,以防止被拦截。

  • 秘密字符串应该在你的应用中保持私密,不能让其他人知道。

  • 任何存储在令牌中的信息都可以被任何拥有秘密的人解码。因此,你永远不应该在令牌中存储敏感信息(如密码或银行账户信息)

三、在express中应用示例

在实际项目中,我们可以使用jsonwebtoken模块来实现身份认证。jsonwebtoken是基于JSON Web Tokens(JWT)协议的实现模块,可以用于生成、解析和验证JWTJWT是一种基于JSON的开放标准(RFC 7519),用于在网络上安全地传输声明。

以下是一个使用expressjsonwebtoken实现身份认证的示例:

const express = require('express');
const jwt = require('jsonwebtoken');

const app = express();

// 定义一个中间件函数,用于身份认证
function verifyToken(req, res, next) {
  // 从请求头中获取token
  const token = req.headers['authorization'];
  if (!token) {
    return res.status(401).send({
      auth: false,
      message: 'No token provided.'
    });
  }

  // 验证token是否有效
  jwt.verify(token, process.env.SECRET_KEY, (err, decoded) => {
    if (err) {
      return res.status(500).send({
        auth: false,
        message: 'Failed to authenticate token.'
      });
    }

    // 将解码的用户信息存储到请求对象中
    req.userId = decoded.id;
    next();
  });
}

// 定义一个路由,需要身份认证
app.get('/api/protected', verifyToken, (req, res, next) => {
  // 返回受保护的数据
  res.status(200).send({
    message: 'Access granted.'
  });
});

// 定义一个路由,用于登录,返回token
app.post('/api/login', (req, res, next) => {
  // 从数据库中获取用户信息
  const user = { id: 123 };

  // 生成token
  const token = jwt.sign({ id: user.id }, process.env.SECRET_KEY, {
    expiresIn: 60 * 60 // token有效期为1小时
  });

  // 返回token
  res.status(200).send({
    auth: true,
    token: token
  });
});

// 启动服务器,监听端口
app.listen(3000, () => {
  console.log('Server started on port 3000');
});

在上述示例中,我们定义了一个中间件函数verifyToken用于身份认证。该函数从请求头中获取token,并通过jsonwebtoken的verify方法验证token是否有效。如果验证通过,则将用户信息存储到请求对象中,以便后续路由函数使用。

我们还定义了两个路由函数,/api/protected/api/login/api/protected需要身份认证才能访问,而/api/login用于登录,并返回生成的token

在实际项目中,我们应该将SECRET_KEY等敏感信息放在环境变量中,以提高安全性。此外,我们还可以使用jsonwebtoken提供的其他功能,如验证token的签名算法、payloadheader等信息。

四、jwt逻辑抽离

在上面的示例中我们用jwt实现了身份认证,但是这只是在一个接口中认证,如果接口多了呢,每次都要将这个认证的中间件加上吗?这样先不说开发实现的累不累,冗余不,单从维护层面来讲,也是很不合理。所以我们应该将认证的逻辑抽离出来,以便于接口调用和维护。具体步骤如下:

1. 新建jwt.js文件

这个文件中就封装三个函数

  • token的生成
  • token的认证
  • 排除哪些接口不需要认证就可以访问,比如/login,
// jwt.js
const jwt = require("jsonwebtoken");
const { promisify } = require("util");
const { uuid } = require("../config/config.default");
const tojwt = promisify(jwt.sign);
const verfiy = promisify(jwt.verify);

// 生成token
module.exports.createToken = async (userinfo) => {
  var token = await tojwt({ userinfo }, uuid, {
    expiresIn: 60 * 60 * 24,
  });
  return token;
};

// jwt认证的中间件
const jwtAuthMiddleware = async (req, res, next) => {
  var token = req.headers.authorization;
  token = token ? token.split("Bearer ")[1] : null;
  if (!token) {
    return res.status(402).json({ error: "请传入token" });
  }
  if (token) {
    try {
      let userinfo = await verfiy(token, uuid);
      req.user = userinfo;
      next();
    } catch (error) {
      res.status("402").json({ error: "无效的token" });
    }
  } else {
    next();
  }
};

// 承认的url排除列表
const jwtAuthExcluedList = ['/api/login', '/api/register'];
// 检查排除列表的中间件
module.exports.jwtAuthExclued = (req, res, next) => {
  // 检查请求 URL 是否在排除 jwtAuth 的列表里面
  if (jwtAuthExcluedList.includes(req.path)){
    next(); // 在列表里,跳过后续中间件
  } else { 
    jwtAuthMiddleware(req, res, next); // 不在列表里,就调用jwt中间件进行身份认证
  }
};

这样封装以后,我们只需要在访问路由之前,添加使用jwtAuthExclued 的中间件就可以实现对接口的token认证,在login接口中调用createToken生成token可以了。

2. 在登录接口中生成token

比如:

  • loginController
// login
// 用户登录
exports.login = async (req, res) => {
  // 客户端数据验证
  // 链接数据库查询
  var dbBack = await User.findOne(req.body)
  if (!dbBack) {
    return res.status(402).json({ error: "邮箱或者密码不正确" })
  }

  dbBack = dbBack.toJSON()
  dbBack.token = await createToken(dbBack)
  res.status(200).json(dbBack)
}

3. 添加全局认证中间件

  • app.js
const express = require("express");
const app = express();
const { jwtAuthExclued } = require("./util/jwt");
const router = require("./router");


// 添加排除jwt中间件
app.use(jwtAuthExclued); 
// 添加路由中间件
app.use('/api', router);

五、jwt和session对比

下面是JWTSession的对比表格:

对比因素JWTSession
存储存储在客户端,不需要服务器保持会话状态。存储在服务器,需要服务器维护会话信息。
安全性加密较严密,但如果token被窃取,攻击者可以任意使用。如果sessionID被窃取,攻击者可以冒充用户登陆。
性能在每次请求时需要验证和解码token,性能较差。只需查找sessionID就能获取会话信息,性能较好。
扩展性在多服务器或者跨域环境中更易扩展。在多服务器环境中需要同步session,扩展性较差。
数据大小JWT的大小比sessionID大,因此需要更多的带宽。sessionID大小稳定,对带宽需求较小。
到期时间可以为每个token设置不同的过期时间。所有session的过期时间通常相同。
客户端存储位置可以存储在Cookie, LocalStorage, SessionStorage中存储在Cookie中。
跨域问题无跨域问题,且对于移动应用而言友好。跨域问题复杂,需要服务器支持CORS。
状态无状态,服务器不需要保存用户信息。有状态,服务器需要保存用户信息。
使用场景用于认证和信息交换,尤其适合单页应用(SPA)和前后端分离的项目主要用于记录用户状态,适配传统的后端渲染的Web服务

总体上来说,JWT适用于前后端分离的API服务,它可以简化服务端的存储需求,并提供更好的跨平台兼容性和可扩展性,同时也能提供安全可靠的身份认证机制。而Session适用于服务器渲染的Web应用,它可以提供更高的安全性和可调用性,同时也能减轻客户端的流量负担。不同的场景需要选择最适合的身份认证方案,根据实际需求进行选择。

六、总结

在本文中,我们探讨了如何在Node.jsExpress框架中使用jsonwebtoken来实现身份认证。我们首先介绍了JWT协议和jsonwebtoken模块的基础知识,然后展示了如何在Express中使用jsonwebtoken来生成、解析和验证JWT。通过在实际项目中的举例,我们演示了如何将jsonwebtoken与路由中间件结合使用,实现基于token的用户身份认证机制。使用jsonwebtoken可以为我们的web应用提供更安全和可靠的用户身份认证方案,同时jwt的优点也是很明显的:无需在服务端保存session信息,具有可扩展性和跨平台兼容性等特点。通过本文的介绍,相信读者已经能够掌握jsonwebtoken的基本使用方法和原理,能够在实际项目中使用jsonwebtoken实现安全可靠的身份认证机制。

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

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

相关文章

Superset基础安装

Superset 介绍 ​ Superset快速,轻巧,直观,并带有各种选项,使各种技能的用户都可以轻松浏览和可视化其数据,从简单的折线图到高度详细的地理空间图。 1、特点 以下是Superset的主要功能的概述: 开箱即用的…

数据库原理与应用(清华版)第一章书后习题

目录 1.1名词解释 1.2简答 1.3判断 1.4选择题 1.5设计一个学生档案管理系统 1.1名词解释 (1)数据库(DB):在计算机的存储设备上合理存放、相关联、有结构的数据集合。 (2)数据库系统(DBS):在计算机系统…

拥抱AIGC,他们有话说——百度李双龙:AIGC将赋能多个场域并惠及千行百业

AIGC在人工智能领域爆火,人工智能技术引领代际变革,⽣成式AI在多个场景落地应用,其中⽣成式⼤语⾔模型(LLM)在通⽤性、多轮对话理解、推理任务中的表现,让世界惊艳。 当前AIGC落地应用进展究竟如何&#x…

蓝牙室内定位-蓝牙定位管理平台功能介绍

蓝牙定位管理平台可以远程快速配置蓝牙定位基站,管理SOS呼救信息,实时定位显示人员、物品位置信息,电子围栏,电子点名,人员或物品移动轨迹记录和查询等。 1、实时定位 在地图上展示人员的实时位置信息,每秒…

团队管理:掌握团队管理的关键神器

什么是团队管理 团队管理是一种协调和领导团队达到共同目标的方法和实践。在今天的竞争激烈的商业环境中,团队管理对于企业的成功至关重要。团队管理不仅仅是指领导者监督团队成员的工作,而是注重协作、沟通和激励,以实现更好的绩效和创造力…

HTML及其标签详解

文章目录 一、HTML简介1、网页1>什么是网页2>什么是HTML 2、Web标准1>为什么需要Web标准2>Web标准的构成 3、HTML语法规范1>基本语法2>标签关系 二、HTML标签1、基本标签2、标题标签3、段落和换行标签4、文本格式化标签5、< div>和< span>标签6、…

css 删除线,价格删除线

text-decoration: line-through;

编写脚本,使用mysqldump实现分库分表备份

进入back_db_v1.sh中 脚本编写如下 运行 验证

ElasticSearch基础篇-安装与基本操作

ElasticSearch基础篇 安装 官网 下载地址 下载完成后对文件进行解压&#xff0c;项目结构如下 进入bin目录点击elasticsearch.bat启动服务 9300 端口为 Elasticsearch 集群间组件的通信端口&#xff0c; 9200 端口为浏览器访问的 http协议 RESTful 端口 打开浏览器&#…

SpringBoot前后端分离项目中通过URL访问Linux服务器上的图片(极简)

新建一个config包&#xff0c;新建WebConfig类&#xff0c;进行如下配置&#xff1a; Configuration public class WebConfig implements WebMvcConfigurer {Overridepublic void addResourceHandlers(ResourceHandlerRegistry registry) {registry.addResourceHandler("…

序列化模块pickle和json有什么区别

目录 什么是序列化模块pickle 什么是序列化模块json pickle和json有什么区别 总结 什么是序列化模块pickle pickle是Python中的内置模块&#xff0c;用于将Python对象序列化和反序列化为字节流。它提供了一种将复杂的数据结构&#xff08;如列表、字典、类实例等&#xff0…

【粒子群算法和蝴蝶算法组合】粒子群混沌混合蝴蝶优化算法研究(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

DevExpress WinForms Scheduler组件中文教程 - 如何与Office 365双向同步?

随着DevExpress WinForms最近的更新&#xff0c;用户可以无缝同步DevExpress WinForms Scheduler与Office 365事件/日程的数据。您可以将用户日程从WinForms Scheduler中导出到Office 365日历&#xff0c;或将Office 365事件/日程导入到Scheduler控件。在同步钱修改用户事件/日…

前端高德地图注册、项目中引入、渲染标记(Marker)and覆盖物(Circle)

首先说明一下&#xff0c;下面的流程只是个人摸索and看文档梳理出来的&#xff0c;并不作为完全正确的流程。 首先&#xff0c;注册 高德开放平台 没有注册的可以点击右上角点击注册&#xff1b; 我们点个人的就ok&#xff1b; 信息完善之后我们到控制台&#xff0c;点击 应…

{“msg“:“invalid token“,“code“:401}

项目场景&#xff1a; 提示&#xff1a;这里简述项目相关背景&#xff1a; {“msg“:“invalid token“,“code“:401} 前端请求 后端接口时&#xff0c; 请求失败&#xff0c;控制台出现如下所示报错信息 问题描述 问题&#xff1a; 控制台报错信息如下所示&#xff1a; …

【基于FFT的自由响应非线性检测方案】使用归零早期FFT的非线性检测研究(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

BPF之路

前言 BPF是内核中的顶级模块, 十分精妙, 相关书籍有限, 而且还都是从应用的视角看待BPF的, 我想写一系列文章, 从一个安全研究员的视角观察BPF, 以帮助更多的人学习和研究 linux内核观测技术一书中, 利用源码树中已有的包裹函数作为入门的例子, 层层包装导致编译时依赖繁多, …

【Nodejs】文件上传

1.初始化准备 1.1 安装依赖 首先创建一个express-multer-upload工程项目&#xff0c;然后在项目中下好各种依赖包。 multer中间件 Multer 是一个 node.js 中间件&#xff0c;用于处理 multipart/form-data 类型的表单数据&#xff0c;它主要用于上传文件。 注意: Multer 不会…

javafx实现自定义的数据拖拽

效果 代码 package cn.juhe.zjsb.test;import javafx.application.Application; import javafx.event.EventHandler; import javafx.scene.Scene; import javafx.scene.SnapshotParameters; import javafx.scene.control.Button; import javafx.scene.control.TextField; impo…

php-golang-rpc jsonrpc和php客户端tivoka/tivoka包实践

golang 代码&#xff1a; package main import ( "fmt" "net" "net/rpc" "net/rpc/jsonrpc" ) type App struct{} type Res struct { Code int json:"code" Msg string json:"msg" Data any json:"…