node.js实现分页,jwt鉴权机制,token,cookie和session的区别
文章目录
- 1. 分⻚功能
- 2. jwt鉴权机制
- 1.jwt是什么
- 2.jwt的应用
- 3.优缺点
- 3. cookie,token,session的对比
1. 分⻚功能
- 为什么要分页
- 如果数据量很⼤,⽐如⼏万条数据,放在⼀个⻚⾯显⽰的话显然不友好,这时候就需要采⽤分⻚显⽰的形式。
- 如每次只显⽰10条数据要实现分⻚功能,实际上就是从结果集中显⽰第1(10条记录作为第1⻚,显⽰第11)20条记录作为第2⻚,以此类推。
- 分⻚实际上就是从结果集中截取出第M~N条记录
- 实现
- 前端实现分⻚功能,需要后端返回必要的数据,如总的⻚数,总的数据量,当前⻚,当前的数据
- 后端的处理逻辑
- 获取⽤⼾参数⻚码数page和每⻚显⽰的数⽬pageSize,其中page是必须传递的参数,pageSize为可选参数,默认为10
- 编写SQL语句,利⽤limit和offset关键字进⾏分⻚查询
- 查询数据库,返回总数据量、总⻚数、当前⻚、当前⻚数据给前端
var mysql = require('mysql'); var connection = mysql.createConnection({host : 'localhost',user : 'root',password : '1q2w3e4r',database : 'test' }); connection.connect(); let param = {pageSize: 20,pageNo: 1 } let pageSize = param.pageSize || 10; let start = (param.pageNo - 1) * pageSize; // 每⼀条数据的起始位置start let sql = `select * from students order by score desc limit ${pageSize} OFFSET ${start}` connection.query(sql, function (error, results, fields) {if (error) throw error;console.log(results); }); connection.end();
⾸先确定每⻚显⽰的数量pageSize,当前⻚的索引pageIndex (从1开始),确定LIMIT 和OFFSET 应该设定的值:- LIMIT 总是设定为pageSize
- OFFSET计算公式为pageSize*(pageIndex-1)
确定了这两个值,就能查询出第N⻚的数
2. jwt鉴权机制
1.jwt是什么
JWT(JSONWebToken),本质就是⼀个字符串书写规范,作⽤是⽤来在⽤⼾和服务器之间传递安全可靠的信息。
- JSON Web Tokens 的组成
在其紧凑的格式中,JSON Web Tokens 由三部分组成,由点 (.)分隔,它们是:Header(标头)Payload(有效载荷 ) Signature(签名)- Header
标头通常由两部分组成:令牌的类型,即 JWT,以及所使用的签名算法,例如 HMAC SHA256 或 RSA.
有效示例{ "alg": "HS256", "typ": "JWT" } - Payload
令牌的第二部分是有效负载,其中包含声明。声明是关于实体(通常是用户)和附加数据的声明。声明分为三种类型:registered(注册声明)、public(公共声明)和private(私人声明).- 已注册声明: 这些是一组预定义的声明,它们不是强制性的,但建议使用,以提供一组有用的、可互操作的声明。其中一些是:
iss(发布者)、
exp(到期时间)、
sub(主题)、
aud(受众)
nbf: 定义在什么时间之前,该jwt都是不可用的.
iat: jwt的签发时间
jti: jwt的唯一身份标识,主要用来作为一次性token,从而回避重放攻击。. - 公共声明: 这些可以由使用 JWT 的人随意定义。但是为了避免冲突,它们应该在IANA JSON Web Token注册表中定义,或者定义为包含抗冲突名称空间的 URI。
- 私人声明: 这些是为在同意使用它们的各方之间共享信息而创建的自定义声明,既不是注册声明也不是公共声明
有效载荷示例{ "sub": "1234567890", "name": "John Doe", "admin": true }
- 已注册声明: 这些是一组预定义的声明,它们不是强制性的,但建议使用,以提供一组有用的、可互操作的声明。其中一些是:
- Signature
要创建签名部分,您必须采用编码标头、编码有效负载、秘码、标头中指定的算法,然后对其进行签名.
- Header
2.jwt的应用
- 安装指令
npm install jsonwebtoken - 加密
参数解析jwt.sign(payload, secretOrPrivateKey, [options, callback])-
payload:可以是表示有效 JSON 的对象文本、缓冲区或字符串
-
secretOrPrivateKey:是一个字符串(utf-8 编码)、缓冲区、对象或 KeyObject,其中包含 HMAC 算法或 PEM 的密钥 RSA 和 ECDSA 的编码私钥
-
options:
- algorithm(默认:HS256)
- expiresIn:以秒为单位或描述时间跨度 Vercel/ms 的字符串 (60, “2 days”, “10h”, “7d”)。
- notBefore:以秒为单位或描述时间跨度 Vercel/ms 的字符串。
- mutatePayload:如果为 true,则 sign 函数将直接修改 payload 对象。如果您在将声明应用于有效负载之后但在将其编码为令牌之前需要对有效负载的原始引用,这将非常有用。
- allowInsecureKeySizes:如果为 true,则允许将模数低于 2048 的私钥用于 RSA
- allowInvalidAsymmetricKeyTypes:如果为 true,则允许与指定算法不匹配的非对称键。此选项仅用于向后兼容,应避免使用。
var jwt = require('jsonwebtoken');const secret = 'xixi' // 私钥var token = jwt.sign({ name: '西西' }, secret);console.log(token, '1111')var token1 = jwt.sign({ name: '西西' }, secret, { algorithm: 'HS512' });console.log(token1, '2222')// 异步jwt.sign({ name: '西西' }, secret, { algorithm: 'HS512' }, function(err, token) {console.log(token, '3333');});var older_token = jwt.sign({ name: '西西', iat: Math.floor(Date.now() / 1000) - 30 }, secret);console.log(older_token, '4444');
加密时效性var jwt = require('jsonwebtoken');const secret = 'xixi' // 私钥let token = jwt.sign({exp: Math.floor(Date.now() / 1000) + (60 * 60),name: '西西'}, secret);console.log(token, '1111')let token1 = jwt.sign({name: '西西'}, secret, { expiresIn: 60 * 60 });console.log(token1, '2222')let tokenh = jwt.sign({name: '西西'}, secret, { expiresIn: '1h' });console.log(tokenh, '3333')
-
- 解密
参数解析jwt.verify(token, secretOrPublicKey, [options, callback])- token是 JsonWebToken 字符串
- secretOrPublicKey是一个字符串(utf-8 编码)、缓冲区或 KeyObject,其中包含 HMAC 算法的密钥或 PEM RSA 和 ECDSA 的编码公钥。
- options
- algorithms:包含允许算法名称的字符串列表。例如。[“HS256”, “HS384”]
- audience:如果要检查 audience (),请在此处提供一个值。可以根据字符串、正则表达式或字符串和/或正则表达式列表检查受众。
- complete:返回具有 decoded 的对象,而不仅仅是有效负载的通常内容。{ payload, header, signature }
- issuer(可选):字段有效值的字符串或字符串数组。iss
- jwtid(可选):如果要检查 JWT ID (),请在此处提供字符串值。jti
- ignoreExpiration:如果不验证令牌的过期时间。true
- ignoreNotBefore…
- subject:如果要检查主题 (),请在此处提供一个值sub
- clockTolerance:检查 and 声明时可容忍的秒数,以处理不同服务器之间的小时钟差异nbfexp
- maxAge:令牌仍然有效的最大允许年龄。它以秒或描述时间跨度 vercel/ms 的字符串表示。
- clockTimestamp:应用作所有必要比较的当前时间(以秒为单位)。
- nonce:如果要检查 Claim,请在此处提供 String 值。它用于 ID 令牌的 Open ID。(Open ID 实施说明nonce)
- allowInvalidAsymmetricKeyTypes:如果为 true,则允许与指定算法不匹配的非对称键。此选项仅用于向后兼容,应避免使用。
let token = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYW1lIjoi6KW_6KW_IiwiaWF0IjoxNzMzMjEwMTc5fQ.24KOMgCK2W6DTUvcotDlP2ciKL_EmA9tTdGJLMZByfc' var decoded = jwt.verify(token, secret); console.log(decoded) // bar let token1 = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYW1lIjoi6KW_6KW_IiwiaWF0IjoxNzMzMjEyMDQ4LCJleHAiOjE3MzMyMTU2NDh9.3gDiIfvDNWbn1DR5a0pZtr0Cwkv_aueHZgui8HVluRo' var decoded1 = jwt.verify(token1, secret); console.log(decoded1)
- 校验
使⽤koa-jwt 中间件进⾏验证,⽅式⽐较简单- 安装指令
npm install koa-jwt - 安装指令
app.use(koajwt({secret: 'test_token' }).unless({ // 配置白名单path: [/\/api\/register/, /\/api\/login/] - 案例
// 服务代码 const Koa = require('koa') const app = new Koa() var jwt = require('jsonwebtoken'); const Router = require('koa-router') var router = new Router(); // 总路由 const koajwt = require('koa-jwt'); const cors = require('koa2-cors') const secret = 'xixi' // 私钥 // 解决跨域 app.use(cors({origin: function(ctx) {// 这里可以根据实际需求设置允许跨域的域名,或者使用函数进行复杂配置// if (ctx.url === '/crossdomain') {// return 'http://example.com';// }return '*'; // 允许所有域},maxAge: 5, // 表示在5秒内不需要再发送预检请求credentials: true, // 允许cookiesallowMethods: ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS'],allowHeaders: ['Content-Type', 'Authorization', 'Accept'], })) // 可以通过unless配置接⼝⽩名单,也就是哪些URL可以不⽤经过校验,像登陆/注册都可以不⽤校验 // 校验的中间件需要放在需要校验的路由前⾯,⽆法对前⾯的URL进⾏校验 app.use(koajwt({secret}))router.post('/api/login_post_json', async (ctx) => {console.log(ctx.request)console.log('abcd');ctx.body = "abcd页"; })app.use(router.routes()).use(router.allowedMethods()); app.listen(8081, function() {console.log('服务启动!端口号:8081') });// html 代码 <!DOCTYPE html> <html lang="en"><head><meta charset="UTF-8" /><meta name="viewport" content="width=device-width, initial-scale=1.0" /><title>Document</title><script src="https://cdn.staticfile.org/jquery/3.4.1/jquery.min.js"></script></head><body><button id="btnPOST">POST</button><script>$(function () {// 2. 测试POST接口let token = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYW1lIjoi6KW_6KW_IiwiaWF0IjoxNzMzMjg5ODE3fQ.rlwgJqUEFXO4_K7FijNELqkOLnOBgGzx1GCn7QY4rXU'$('#btnPOST').on('click', function () {$.ajax({type: 'POST',url: 'http://127.0.0.1:8081/api/login_post_json',headers: {'Content-Type': 'application/json;charset=utf-8', Authorization: `Bearer ${token}` }, // 注:需要在请求头中使用Authorization字段并使用Bearer模式来发送token,data: { name: '西西', author: '11111'},success: function (res) {console.log(res)},})})})</script></body> </html>
- 安装指令
3.优缺点
优点:
- json具有通⽤性,所以可以跨语⾔
- 组成简单,字节占⽤⼩,便于传输
- 服务端⽆需保存会话信息,很容易进⾏⽔平扩展
- ⼀处⽣成,多处使⽤,可以在分布式系统中,解决单点登录问题
- 可防护CSRF攻击
缺点:
- payload部分仅仅是进⾏简单编码,所以只能⽤于存储逻辑必需的⾮敏感信息
- 需要保护好加密密钥,⼀旦泄露后果不堪设想
- 为避免token被劫持,最好使⽤https协议
3. cookie,token,session的对比
Cookie、Token和Session是Web开发中常用的三种用户会话管理机制
-
Cookie
Cookie 是一种由服务器发送到客户端浏览器的小数据片段,用于存储用户的状态信息。
它主要用于跟踪用户会话、存储用户偏好设置、记住用户登录状态等。
优点- 存储在客户端,服务器负担较轻。
- 每次请求时自动发送,适合无状态应用。
缺点
- 容量有限,单个Cookie的大小通常不超过4KB。
- 安全性较低,容易被篡改或遭受跨站请求伪造(CSRF)攻击
-
Token
Token是服务端生成的一串字符串,用作客户端进行请求的令牌。当用户第一次登录后,服务器生成一个Token并将此Token返回给客户端,以后客户端只需带上这个Token前来请求数据即可,无需再次带上用户名和密码。
优点- 无状态,适合无状态和分布式系统。
- 安全性较高,因为Token通常经过加密处理。
缺点
- 每次请求都需要验证Token,可能会增加服务器的计算负担
-
Session
Session是在服务器端存储用户会话信息的机制。当用户访问网站时,服务器会为该用户创建一个唯一的Session,并生成一个Session ID。这个Session ID用于在多个请求之间保持用户的会话状态。
优点- 存储在服务器端,安全性较高,因为数据不存储在客户端。
- 可以存储大量数据,没有容量限制。
缺点
- 占用服务器资源,可能影响性能
| 特性 | Cookie | Session | Token |
|---|---|---|---|
| 存储位置 | 客户端存储 | 服务器端存储,客户端存储 Session ID | 客户端存储 |
| 安全性 | 易受 CSRF 攻击,易被篡改 | 更安全,敏感数据存储在服务器端 | 一旦泄露可能被盗用 |
| 容量 | 4KB 限制 | 服务器端可以存储更多数据 | 受限于 Token 大小,但一般较小 |
| 性能 | 自动随请求发送 | 服务器需要维护状态,增加负担 | 无状态机制,适合分布式应用 |
| 使用场景 | 适合简单的用户状态管理 | 适合需要存储大量用户数据的应用 | 适合需要无状态认证和分布式系统的应用 |
相关文章:
node.js实现分页,jwt鉴权机制,token,cookie和session的区别
文章目录 1. 分⻚功能2. jwt鉴权机制1.jwt是什么2.jwt的应用3.优缺点 3. cookie,token,session的对比 1. 分⻚功能 为什么要分页 如果数据量很⼤,⽐如⼏万条数据,放在⼀个⻚⾯显⽰的话显然不友好,这时候就需要采⽤分⻚…...
34 基于单片机的指纹打卡系统
目录 一、主要功能 二、硬件资源 三、程序编程 四、实现现象 一、主要功能 基于STC89C52RC,采用两个按键替代指纹,一个按键按下,LCD12864显示比对成功,则 采用ULN2003驱动步进电机转动,表示开门,另一个…...
【Linux】用户操作命令
声明:以下内容均学习自《Linux就该这么学》一书 1、管理员root Linux系统的管理员之所以是root,并不是因为它的名字叫root,而是因为该用户的身份号码UID(User IDentification)的数值是0。UID相当于身份证号码&#x…...
Y20030018基于Java+Springboot+mysql+jsp+layui的家政服务系统的设计与实现 源代码 文档
家政服务系统的设计与实现 1.摘要2.开发目的和意义3.系统功能设计4.系统界面截图5.源码获取 1.摘要 随着人们生活水平的提高,老龄化、少子化等多重因素影响,我国对家政服务人群的需求与日俱增。家政服务行业对我国的就业和社会效益贡献也与日俱增&#…...
windows部署PaddleSpeech详细教程
windows安装paddlespeech步骤: 1. 安装vs c编译环境 对于 Windows 系统,需要安装 Visual Studio 来完成 C 编译环境的安装。 Microsoft C Build Tools - Visual Studio 2. 安装conda conda create -y -p paddlespeech python3.8 conda activate pad…...
线程条件变量 生产者消费者模型 Linux环境 C语言实现
只能用来解决同步问题,且不能独立使用,必须配合互斥锁一起用 头文件:#include <pthread.h> 类型:pthread_cond_t PTHREAD_COND_INITIALIZER 初始化 初始化:int pthread_cond_init(pthread_cond_t * cond, NULL);…...
C++ packaged_task
packaged_task 是 C11 标准库中引入的一个模板类,它用于将可调用对象(如函数、lambda 表达式、函数对象或绑定表达式)包装起来,并允许异步地获取其结果packaged_task 类提供了一种方便的方式来创建任务,这些任务可以被…...
【联表查询】.NET开源 ORM 框架 SqlSugar 系列
.NET开源 ORM 框架 SqlSugar 系列 【开篇】.NET开源 ORM 框架 SqlSugar 系列【入门必看】.NET开源 ORM 框架 SqlSugar 系列【实体配置】.NET开源 ORM 框架 SqlSugar 系列【Db First】.NET开源 ORM 框架 SqlSugar 系列【Code First】.NET开源 ORM 框架 SqlSugar 系列【数据事务…...
嵌入式C编程:宏定义与typedef的深入对比与应用
目录 一、宏定义(Macro Definition) 1.1. 特点与应用 1.1.1 定义常量 1.1.2 定义函数式宏 1.1.3 条件编译 1.2. 作用范围和生命周期方面 1.3. 应用注意事项 二、typedef 2.1. 特点与应用 2.1.1 简化类型声明 2.1.2 提高代码可读性 2.1.3 实现…...
高级java每日一道面试题-2024年12月03日-JVM篇-什么是Stop The World? 什么是OopMap? 什么是安全点?
如果有遗漏,评论区告诉我进行补充 面试官: 什么是Stop The World? 什么是OopMap? 什么是安全点? 我回答: 在Java虚拟机(JVM)中,Stop The World、OopMap 和 安全点 是与垃圾回收(GC)和性能优化密切相关的概念。理…...
【openGauss︱PostgreSQL】openGauss或PostgreSQL查表、索引、序列、权限、函数
【openGauss︱PostgreSQL】openGauss或PostgreSQL查表、索引、序列、权限、函数 一、openGauss查表二、openGauss查索引三、openGauss查序列四、openGauss查权限五、openGauss或PostgreSQL查函数六、PostgreSQL查表七、PostgreSQL查索引八、PostgreSQL查序列九、PostgreSQL查权…...
Dataset用load_dataset读图片和对应的caption的一个坑
代码: data_files {} if args.train_data_dir is not None:data_files["train"] os.path.join(args.train_data_dir, "**")dataset load_dataset("imagefolder",data_filesdata_files,cache_dirargs.cache_dir,) 数据࿱…...
【信息系统项目管理师】第7章:项目立项管理 考点梳理
文章目录 7.1 项目建议与立项申请7.2 项目可行性研究7.2.1 可行性研究的内容7.2.2 初步可行性研究7.2.3 详细可行性研究(重点) 7.3 项目评估与决策 【学习建议】本章大概考选择题2分左右,有可能考案例题。论文早年考过。本章知识点比较集中&a…...
知识库、提示词对大语言模型的影响测试
简介 通过对比有无知识库,测试大语言模型的回答 有无提示词对比测试 前提 大语言模型:Qwen1.5-1.8B-Chat-GPTQ-Int4 GPU:1650super,显存4G 提问:华为mate70 没有提示词 回答的内容如下 “华为mate70pro和mate40p…...
vistat-监控和分析网络状态
vistat 是一个用于监控和分析网络状态的工具,通常用于查看网络接口、流量、连接等实时数据。 原理:用户态调用系统接口获取内核中的网络统计信息。 核心功能:网络接口流量监控、查看连接状态、带宽使用分析。 使用方法: 查看接…...
EasyAnimateV5 视频生成大模型原理详解与模型使用
在数字内容创作中,视频扮演的角色日益重要。然而,创作高质量视频通常耗时且昂贵。EasyAnimate 系列旨在利用人工智能技术简化这一过程。EasyAnimateV5 建立在其前代版本的基础之上,不仅在质量上有所提升,还在多模态数据处理和跨语…...
水稻和拟南芥生命周期中单碱基分辨率的m6A定量分析-文献精读88
Quantitative profiling of m6A at single base resolution across the life cycle of rice and Arabidopsis 水稻和拟南芥生命周期中单碱基分辨率的m6A定量分析 水稻参考基因组(日本晴品种)-CSDN博客 “Xian”(籼)和“Geng”&…...
学习threejs,使用canvas更新纹理
👨⚕️ 主页: gis分享者 👨⚕️ 感谢各位大佬 点赞👍 收藏⭐ 留言📝 加关注✅! 👨⚕️ 收录于专栏:threejs gis工程师 文章目录 一、🍀前言1.1 ☘️Texture 贴图 二、…...
【笔记2-3】ESP32 bug:PSRAM chip not found or not supported 没有外部PSRAM问题解决
主要参考b站宸芯IOT老师的视频,记录自己的笔记,老师讲的主要是linux环境,但配置过程实在太多问题,就直接用windows环境了,老师也有讲一些windows的操作,只要代码会写,操作都还好,开发…...
大数据hadoop、spark、flink、kafka发展的过程
将sql 代发翻译成java 程序 将python 程序通过pyspark框架翻译成java 程序,然后运行在spark计算框架上...
OkHttp 中实现断点续传 demo
在 OkHttp 中实现断点续传主要通过以下步骤完成,核心是利用 HTTP 协议的 Range 请求头指定下载范围: 实现原理 Range 请求头:向服务器请求文件的特定字节范围(如 Range: bytes1024-) 本地文件记录:保存已…...
《基于Apache Flink的流处理》笔记
思维导图 1-3 章 4-7章 8-11 章 参考资料 源码: https://github.com/streaming-with-flink 博客 https://flink.apache.org/bloghttps://www.ververica.com/blog 聚会及会议 https://flink-forward.orghttps://www.meetup.com/topics/apache-flink https://n…...
数据库分批入库
今天在工作中,遇到一个问题,就是分批查询的时候,由于批次过大导致出现了一些问题,一下是问题描述和解决方案: 示例: // 假设已有数据列表 dataList 和 PreparedStatement pstmt int batchSize 1000; // …...
ABAP设计模式之---“简单设计原则(Simple Design)”
“Simple Design”(简单设计)是软件开发中的一个重要理念,倡导以最简单的方式实现软件功能,以确保代码清晰易懂、易维护,并在项目需求变化时能够快速适应。 其核心目标是避免复杂和过度设计,遵循“让事情保…...
【SSH疑难排查】轻松解决新版OpenSSH连接旧服务器的“no matching...“系列算法协商失败问题
【SSH疑难排查】轻松解决新版OpenSSH连接旧服务器的"no matching..."系列算法协商失败问题 摘要: 近期,在使用较新版本的OpenSSH客户端连接老旧SSH服务器时,会遇到 "no matching key exchange method found", "n…...
mac 安装homebrew (nvm 及git)
mac 安装nvm 及git 万恶之源 mac 安装这些东西离不开Xcode。及homebrew 一、先说安装git步骤 通用: 方法一:使用 Homebrew 安装 Git(推荐) 步骤如下:打开终端(Terminal.app) 1.安装 Homebrew…...
go 里面的指针
指针 在 Go 中,指针(pointer)是一个变量的内存地址,就像 C 语言那样: a : 10 p : &a // p 是一个指向 a 的指针 fmt.Println(*p) // 输出 10,通过指针解引用• &a 表示获取变量 a 的地址 p 表示…...
Linux 下 DMA 内存映射浅析
序 系统 I/O 设备驱动程序通常调用其特定子系统的接口为 DMA 分配内存,但最终会调到 DMA 子系统的dma_alloc_coherent()/dma_alloc_attrs() 等接口。 关于 dma_alloc_coherent 接口详细的代码讲解、调用流程,可以参考这篇文章,我觉得写的非常…...
6️⃣Go 语言中的哈希、加密与序列化:通往区块链世界的钥匙
Go 语言中的哈希、加密与序列化:通往区块链世界的钥匙 一、前言:离区块链还有多远? 区块链听起来可能遥不可及,似乎是只有密码学专家和资深工程师才能涉足的领域。但事实上,构建一个区块链的核心并不复杂,尤其当你已经掌握了一门系统编程语言,比如 Go。 要真正理解区…...
Spring Boot + MyBatis 集成支付宝支付流程
Spring Boot MyBatis 集成支付宝支付流程 核心流程 商户系统生成订单调用支付宝创建预支付订单用户跳转支付宝完成支付支付宝异步通知支付结果商户处理支付结果更新订单状态支付宝同步跳转回商户页面 代码实现示例(电脑网站支付) 1. 添加依赖 <!…...
