node 第十九天 使用node插件node-jsonwebtoken实现身份令牌jwt认证

news2024/12/23 4:19:13
  1. 实现效果如下

    前后端分离token登录身份验证效果演示

  2. node-jsonwebtoken
    基于node实现的jwt方案, jwt也就是jsonwebtoken, 是一个web规范可以去了解一下~
    一个标准的jwt由三部分组成
    第一部分:头部
    第二部分:载荷,比如可以填入加密后的用户信息 (填入的信息一定要加密,jwt本质上是明文传输, 用于防篡改而不是做验证
    第三部分:签名信息
    在这里插入图片描述
    使用node-jsonwebtoken的理由
    开源
    实现了服务端设置jwt有效时间,服务端主动作废token

  3. 签名jwt
    服务端使用密钥加密jwt的签名部分然后将jwt发送给客户端,客户端将jwt保存,可以保持在localStorage或者Cookie,由于服务端能够控制jwt过期时间(这里应该是代码实现而不是jwt的标准), 所以放在localStorage或许是一种更现代化的解决方案

  4. 标准jwt防篡改防伪造验证流程
    服务端通过key生成一个签名,通过 签名+信息=jwt
    jwt发到客户端
    客户端带jwt到服务端验证
    服务端通过key和jwt的信息再生成一次签名和jwt的签名做对比
    对比成功, 验证通过
    对比失败, 验证不通过
    至始至终key只存在于服务端,只要key不泄露, jwt就无法被篡改被伪造

  5. 到这里, 我们已经实现了jwt登录验证, 但是需要注意的是jwt是明文传输的,也就是说用户的密码暴露在token里面, 更进一步, 我们可以对jwt的载荷再加密一次,即使token暴露,用户的密码也不会暴露,服务端只要作废这个token就可以了。

  6. 使用第十七天的教程对jwt的载荷进行加密

  7. 基于这些可以轻松实现无感刷新token

  8. jwt 是一个身份令牌而不是一种安全手段

  9. 至此用户密码的暴露只存在于用户登录的那个接口请求过程,需要前端配合处理例如使用JSEncrypt

  10. 到底哪些加密是必须的哪些是无用的, 还需要具体业务来梳理

  11. 贴一下后端主模块代码

    var createError = require('http-errors');
    var express = require('express');
    var path = require('path');
    var cookieParser = require('cookie-parser');
    var logger = require('morgan');
    
    const cors = require('cors');
    const jwt = require('jsonwebtoken');
    const fs = require('fs');
    
    const { encrypt, decrypt } = require('./rsa');
    
    var indexRouter = require('./routes/index');
    var usersRouter = require('./routes/users');
    
    var app = express();
    
    // view engine setup
    app.set('views', path.join(__dirname, 'views'));
    app.set('view engine', 'hbs');
    app.use(logger('dev'));
    app.use(express.json());
    app.use(express.urlencoded({ extended: false }));
    app.use(cookieParser());
    app.use(express.static(path.join(__dirname, 'public')));
    app.use(
      cors({
        origin: true, //true 设置为 req.origin.url
        methods: 'GET,HEAD,PUT,PATCH,POST,DELETE', //容许跨域的请求方式
        allowedHeaders: 'x-requested-with,Authorization,token, content-type, x-token', //跨域请求头
        preflightContinue: false, // 是否通过next() 传递options请求 给后续中间件
        maxAge: 1728000, //options预验结果缓存时间 20天
        credentials: true, //携带cookie跨域
        optionsSuccessStatus: 200 //options 请求返回状态码
      })
    );
    
    const verifyOptions = {};
    
    const jwtKey = fs.readFileSync(path.join(process.cwd(), '/auth/jwt.cer'), 'utf-8');
    
    app.post('/login', (req, res, next) => {
      const { user, pwd } = req.body;
      // 加密jwt(token)载荷
      const encrypt_info = encrypt(JSON.stringify({ user, pwd }));
      delete verifyOptions.maxAge;
      // 签发jwt(token)
      const token = jwt.sign({ info: encrypt_info }, jwtKey, {
        // 有效时间
        expiresIn: '60s'
      });
      res.send({
        msg: 'ok',
        token
      });
    });
    
    app.post('/request', (req, res, next) => {
      const token = req.headers['x-token'];
      // 验证jwt(token)
      jwt.verify(token, jwtKey, verifyOptions, (err, decoded) => {
        if (err) {
          res.send({
            msg: 'token error'
          });
          return;
        }
        // 解密jwt(token)载荷 处理业务
        const decrypt_info = JSON.parse(decrypt(decoded.info));
        res.send({
          msg: `welcome ${decrypt_info.user}`
        });
      });
    });
    
    app.post('/logout', (req, res, next) => {
      const token = req.headers['x-token'];
      // 作废jwt(token)
      verifyOptions.maxAge = '0s';
      jwt.verify(token, jwtKey, verifyOptions, (err, decoded) => {
        res.send({
          msg: 'logout'
        });
      });
    });
    
    app.use('/', indexRouter);
    app.use('/users', usersRouter);
    
    // catch 404 and forward to error handler
    app.use(function (req, res, next) {
      next(createError(404));
    });
    
    // error handler
    app.use(function (err, req, res, next) {
      // set locals, only providing error in development
      res.locals.message = err.message;
      res.locals.error = req.app.get('env') === 'development' ? err : {};
    
      // render the error page
      res.status(err.status || 500);
      res.render('error');
    });
    
    module.exports = app;
    

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

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

相关文章

VS2022 配置 OpenCV并开始第一个程序

VS2022安装 首先下载 VisualStudioSetup.exe 下载连接:Visual Studio 2022 IDE - 适用于软件开发人员的编程工具 点击上面的链接即可进入到下载页面。进入到下载页面,可看到有几个版本可选,如下: 我选择的是企业版:E…

23年宁波职教中心CTF竞赛-决赛

Web 拳拳组合 进去页面之后查看源码,发现一段注释,写着小明喜欢10的幂次方,那就是10、100、1000、10000 返回页面,在点击红色叉叉的时候抓包,修改count的值为10、100、1000、10000 然后分别获得以下信息 ?count1…

Web(5)Burpsuite之文件上传漏洞

1.搭建网站:为网站设置没有用过的端口号 2.中国蚁剑软件的使用 通过一句话木马获得权限 3.形象的比喻(风筝) 4.实验操作 参考文章: 文件上传之黑名单绕过_文件上传黑名单绕过_pigzlfa的博客-CSDN博客 后端验证特性 与 Window…

Jmeter 吞吐量Per User作用

第一点:Per User仅在Total Execution时生效 第二点:Per User 选中后 聚合报告中将统计的的样本数将变成线程组配置的线程数*吞吐量控制器配置的执行样本数量(前提是线程组配置执行接口的次数线程数*循环数 大于吞吐量控制器配置的执行样本数…

英孚成人英语水平测试分为几个级别?

目录 一、1-3入门级二、4-6初级三、7-9中级四、10-12中高级五、13-15高级六、16精通级 英孚成人英语正式学习前老师会让学员进行等级测试,通过测试结果帮助学员制定学习计划。那么英孚成人英语水平测试分几个级别呢?这里大家一起了解一下。 英孚成人英语…

zabbix的安装配置,邮件告警,钉钉告警

zabbix监控架构 zabbix优点 开源,无软件成本投入server对设备性能要求低支持设备多,自带多种监控模板支持分布式集中管理,有自动发现功能,可以实现自动化监控开放式接口,扩展性强,插件编写容易当监控的item…

装修干货|卧室常见3个软装搭配问题。福州中宅装饰,福州装修

引言 作为一名软装设计师,我对卧室的家具及软装布置颇有心得,现在就给你们带来卧室装修设计一些小技巧: 1. 床;衣柜;床头柜的摆放 床的摆放位置非常重要,一般要放在离窗户稍远的地方,避免直接…

[MySQL] MySQL表的约束

在前面的文章中提到了约束,是通过数据类型对字段产生的约束。但是数据类型约束很单一,需要有一些额外的约束,更好的保证数据的合法性,从业务逻辑角度保证数据的正确性。于是就引入了表的约束。 表的约束很多,这里主要介…

「Verilog学习笔记」使用3-8译码器①实现逻辑函数

专栏前言 本专栏的内容主要是记录本人学习Verilog过程中的一些知识点,刷题网站用的是牛客网 timescale 1ns/1nsmodule decoder_38(input E1_n ,input E2_n ,input E3 ,input A0 ,input A1…

Vue.js2+Cesium1.103.0 十四、绘制视锥,并可实时调整视锥姿态

Vue.js2Cesium1.103.0 十四、绘制视锥&#xff0c;并可实时调整视锥姿态 Demo <template><divid"cesium-container"style"width: 100%; height: 100%;"><divclass"control"style"position: absolute;right: 50px;top: 50px…

世微 降压恒流驱动IC 景观亮化洗墙灯舞台灯汽车灯LED照明 AP5199S

1. 特性 支持高辉调光&#xff0c;调光比 平均电流工作模式 高效率&#xff1a;最高可达 95% 输出电流可调范围 60mA~12A 最大工作频率 1MHz 恒流精度≤3% 支持 PWM 封装&#xff1a;SOP8 2. 应用领域 景观亮化洗墙灯 舞台调光效果灯 汽车照明 3. 说明 AP5199S…

案例精选|聚铭综合日志分析系统提升长沙(中国水务)集团有限公司信息安全审计效率

长沙&#xff08;中国水务&#xff09;集团有限公司是经宁乡县自来水公司改制后成立的城市供水企业&#xff0c;隶属香港联合交易所主板上市公司-中国水务集团有限公司。目前&#xff0c;公司拥有2个水厂5个加压站&#xff0c;日供水能力为28万吨/日&#xff0c;供水范围已从城…

代码随想录二刷 | 数组 | 数组理论基础

代码随想录二刷 &#xff5c; 数组 &#xff5c; 数组理论基础 数组是存放在连续内存空间上的相同类型数据的集合。可以通过下标索引的方式获取到下标对应的数据。 数组的下标都是从0开始的 数组内存空间的地址是连续的 因为数组的在内存空间的地址是连续的&#xff0c;所以我们…

ubuntu下载conda

系统&#xff1a;Ubuntu18.04 &#xff08;1&#xff09;下载安装包 wget https://mirrors.tuna.tsinghua.edu.cn/anaconda/archive/Anaconda3-2021.11-Linux-x86_64.sh 报错错误 403&#xff1a;Forbidden 解决方法 wget -U NoSuchBrowser/1.0 https://mirrors.tuna.tsingh…

关于SPJ表的数据库作业

打字不易&#xff0c;且复制且珍惜 建表 use 库名;create table S( --供应商 SNO char(6) not null, SNAME char(10) not null, STATUS INT, CITY char(10), primary key(SNO));create table P( --零件 PNO char(6) not null, PNAME char(12)not null, COLOR char(4), WEIGHT…

章鱼网络在 NEARCON23 发布 Octopus 2.0

香港时间2023年11月8日12点&#xff0c;章鱼网络举行第15期 Community Call。 我们在10月8日庆祝了章鱼网络主网上线二周年&#xff0c;并参加了激动人心的 Cosmoverse2023 活动。最重要的是&#xff0c;我们在 Octopus 2.0 的开发中取得了重大进展。 11月8日 Community Call …

为什么我学了几天 STM32 感觉一脸茫然?

为什么我学了几天 STM32 感觉一脸茫然&#xff1f; 刷到过b站的zhihui君吧&#xff0c;去看他的回答&#xff0c;他的第一块开发板是arduino&#xff0c;这种级别的人物&#xff0c;在国内也是大神级了&#xff0c;最早学电子方向也是用的arduino。最近很多小伙伴找我&#xff…

storage和正则表达式

一、Storage 1.认识Storage WebStorage主要提供了一种机制&#xff0c;可以让浏览器提供一种比cookie更直观的key、value存储方式&#xff1a; localStorage&#xff1a;本地存储&#xff0c;提供的是一种永久性的存储方法&#xff0c;在关闭掉网页重新打开时&#xff0c;存…

【C++】泛型编程 ⑥ ( 类模板 | 类模板语法 | 代码示例 )

文章目录 一、类模板1、类模板引入2、声明类模板语法3、调用类模板语法 二、代码示例 - 类模板1、代码示例2、执行结果 一、类模板 1、类模板引入 类模板 与 函数模板 的 作用类似 , 当 多个类 功能相同 , 只是数据类型不同 , 此时可以 定义一个类模板 代替 定义多个类 ; 借助…

DRF纯净版项目搭建和配置

一、安装模块和项目 1.安装模块 pip install django pip install djangorestframework pip install django-redis # 按需安装 2.开启项目和api (venv) PS D:\pythonProject\env_api> django-admin startproject drf . (venv) PS D:\pythonProject\env_api> python ma…