Express 中使用JWT进行登录验证

news2025/1/14 17:58:00


cookie 篇  :  Node.js 中 cookie的验证登录      |        session 篇 :  Node.js 中 session验证登录


         在前面讲过了两种验证登录的方式,其一是cookie,其二是session;那么在讲JWT之前先来简单的回顾这两种方式区别;cookie和session的区别在于cookie是存储在客户端的而session是存在于服务器端的,cookie的安全性比session的安全性低;那么在这里要多提关于session的内容,我们知道session的工作原理(如下):

        session需要配合cookie才能实现,同时cookie是不支持跨域访问(具有独立性),所以当涉及到前后端跨域请求后端接口时,难免需要做其他的一些额外配置,才能实现跨域的session认证;当然如果后端接口不存在跨域问题,那么就推荐使用session的这种认证机制,如果没有的话又觉得配置太麻烦可以使用接下来要讲的JWT( JSON Web Token).

JWT (JSON Web Token)

        JWT是目前最流行的跨域认证解决方案,那么先来了解一下它的工作原理(如图):

        将用户的信息进行验证,验证成功后会将用户信息进行加密,生成Token之后服务器将它响应给到客户端,客户端拿到这个Token之后将它保存起来,可保存在LocalStorage或SessionStorage中,那么在下次客户端再次发起请求之后,会再将未过期的Token发给服务器去还原验证,如果验证成功服务器会将请求相应的用户信息内容返回给客户端这样一个过程。

JWT组成

        JWT是由3个部分组成的,分别为 Header,Payload,Signature ;

 Express 中安装引入JWT

        先来创建express框架的项目环境:

安装导入 JWT 相关的包

 命令如下:

npm install jsonwebtoken express-jwt

jsonwebtoken包是用于生成JWT字符串;express-jwt包是将jwt字符串进行解析还原为JSON对象;

引入如下:

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

定义密钥

         为了保证JWT字符串的安全性,防止JWT字符串在网络传输过程中被人破解,就需要定义一个用于加密和解密的secret密钥;

  • 当生成JWT字符串的时候,需要使用secret密钥对用户信息进行加密,最终得到加密好的JWT字符串;
  • 当把JWT字符串解析还原成JSON对象的时候,需要使用secret密钥进行解密;
  • secret密钥的本质就是一个字符串(越复杂越好);

        那么这里密钥的设置方式可以有很多种,可以是通过一个文件存放,然后通过fs模板读取,使用openSSL生成私钥然后通过私钥生成公钥等,那么在接下来的案例当中会使用一种比较简单的尽可能的在本篇当中能让你会基本的使用和了解到这个jwt,下面就来开始案例:

Express框架中jwt验证登录

        这里将之前cookie和session中使用过的案例进行改造:首先进入首页会检测是否在本地存储了登录的token,如果则会提示去登录,进入登录页面,输入错误的信息会有弹窗提示,输入正确的信息后会提交到服务器去验证,验证成功之后会生成一个token返回去给客户端,通过客户端来查看一下token信息,以及token失效后会提示然后返回到登录处去;

         那如果还未清楚,下面就一同来通过代码来进一步了解:现在 /public/index.html 编写以下该文件;

index.html 首页编写

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>CSDN</title>
    <script src="https://cdn.staticfile.org/jquery/1.10.2/jquery.min.js"></script>
    <script src="javascripts/checklogin.js"></script>
    <link rel="stylesheet" href="stylesheets/index.css"/>
</head>
<body>
    <header>
        <h3>首页</h3>
    </header>
    <div class="content">
        <p>正在维修中...</p>         
    </div>
</body>
</html>

login.html 登陆页编写

        同样在 /public/login.html 下编写文件;

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>登录</title>
    <link rel="stylesheet" href="stylesheets/login.css"/>
</head>
<body>
    <div class="content">
        <div class="head">
            <img src="../images/CSDN.png" alt="" srcset="">
        </div>
        <form action="">
            <div class="form-input">
                <div class="form-data">
                    <span>账户:</span>
                </div>
                <input type="text" class="input-text" name="username" value=""/>
            </div>
            <div class="form-input">
                <div class="form-data"> 
                    <span>密码:</span>
                </div>
                <input type="password" class="input-text" name="password" value=""/>
            </div>
        </form>
            <input type="submit" class="form-submit" value="登录" id="btuLogin" />
    </div>
</body>
<script src="https://cdn.staticfile.org/jquery/1.10.2/jquery.min.js"></script>
<script src="javascripts/login.js"></script>
</html>

        编写完成以上两个文件之后,在前面讲过可以通过app.js中来通过app.use(express.static(path.json(__dirname,'public'))) 配置来托管静态资源信息;那么在浏览器来访问时候的路径不需要添加public,否则访问不到;

模拟登录用户数据json

        在 /public/user.json 下编写该文件:

// user.json文件
[
    {
        "id":"1001",
        "username":"YAN",
        "password":"yan"
    },
    {
        "id":"1002",
        "username":"SEN",
        "password":"sen"
    },
    {
        "id":"1003",
        "username":"LIN",
        "password":"lin"
    }
]

        接下来的登录会通过接收的数据与读取该json数据进行遍历比对来验证是否存在该用户;

路由配置

        首先就是客户端将登录的信息提交到后端验证,可以通过POST请求方式,后端通过req.body获取对应的信息,紧接着使用fs文件系统模块来读取user.json文件的进而遍历提交的信息是否在user.json中存在,最后返回状态码,在存在当中还需要生成一个token来发送给客户端,让客户端保存;

var express = require('express');
var router = express.Router();
const fs = require('fs');
const {resolve} = require('path');
var jwt = require('jsonwebtoken');
var {expressjwt : expressJWT} = require('express-jwt');

var secret = 'The author is lhxz';

router.use(expressJWT({secret,algorithms:["HS256"]}).unless({path:['/login']}));

// 配置中间件
router.use(function(err,req,res,next){
  // token解析失败
  if(err.name === 'UnauthorizedError'){
    return res.send({code:1,msg:' 登录过期 | 无效token '})
  }
  res.send({status:500,message:'未知的错误'});
  next();
})

router.get('/checklogin',function(req,res,next){
  console.log(req.auth);
  res.send({
    code:0,
    msg:'ok',
    data:req.auth
  })
})

/* GET home page. */
router.get('/', function(req, res, next) {
  res.render('index', { title: 'Express' });
});

router.post('/login',function(req,res,next){
  // 获取前台信息;
  let username = req.body.username,password = req.body.password;

  // 读取
  let result = fs.readFileSync(resolve(__dirname,'../public/user.json'));
  let results = JSON.parse(result);

  // 遍历
  for(var i = 0;i<results.length;i++){
    if(username == results[i].username && password == results[i].password){
        // 验证成功
        res.send({
          code:0,
          msg:'ok',
          // 返回token
          token:jwt.sign({username:results[i].username,password:results[i].password},secret,{expiresIn:'120s'})
        })
    }
  }
  if(i==results.length){
    res.send({
      code:1,
      msg:'error'
    })
  }
})

module.exports = router;

 [ 以上就是采用对称加密,就是生成和解析的都是同一把钥匙(密钥);var secret = 'The author is lhxz' 就是密钥,通过jwt.sign()方法就可以生成token发送给客户端,客户端每次在访问有权限的接口(例如在主页时你需要有token才能访问)的时候,都需要主动通过请求头中的Authorization字段,将token发送去到服务器去验证,在上面已经提及到了这个express-jwt中间件,服务器可以通过它来自动将客户端发过来的Token解析为JSON对象,以上代码就是通过配置的:router.use(expressJWT({secret,algorithms:["HS256"]}).unless({path:['/login']})),这样一来就会很方便,当然在最后面的演示当中会来演示通过官网验证;

登录获取token

         在登录页面当中填写信息,然后点击登录,提交信息到服务器去验证;在/javascripts/login.js 编写该文件:

// login.js文件
$('#btuLogin').click(function(){
    $.ajax({
        type:'post',
        url:'/login',
        data:$('form').serialize()  // username=xx&password=xx
    }).then(function(res){
        if(res.msg == 'ok'){
            // 跳转
            localStorage.setItem('login_Token',res.token);
            location.href = '/index.html'
        }else{
            alert("账户或密码错误,请重新输入");
            // 清空
            $('input[name=username]').val('');
            $('input[name=password]').val('');
            // 获取焦点
            $('input[name=username]').focus();
        }
    })
})

检测是否有token

        进入页面之后通过在LocalStorage中去判断是否有login_Token,有的话就去验证一下,验证成功的话则会有 "欢迎回来!" 的提示,如果没有token的存在则需要提示它未登录需要先去进行登录然后让服务器发送token给客户端保存;

// 判断是否有token
let tk = localStorage.getItem('login_Token');
if(tk!= null){
    // 有token去验证
    let rs = localStorage.getItem('login_Token');
    $.ajax({
        type:'GET',
        url:'/checklogin',
        headers:{
            "Authorization":"Bearer "+rs
        }
    }).then(function(res){
       if(res.msg == 'ok'){
            alert('欢迎回来!');
       }else{
            alert(res.msg);
            location.href = "/login.html"
       } 
    })

}else{
    // 没有跳转登录
    alert("未登录,请先登录...");
    location.href = '/login.html';
}

Express - JWT 测试演示

1. 启动项目 —— 跑起来

2. 浏览器中输入 http://127.0.0.1:3000/index.html

        - 无token —— 登录失败

        - 跳转 login.html 登录页面 —— 输入错误信息登录提示

         - 输入正确信息之后是否正常跳转,且是否保存了token?

token的验证是怎样的呢?可以来带jwt的官网测试一下,将刚刚拿到的这串token测试一下:

JWT官网 选择 【Debugger】: JSON Web Tokens - jwt.io

        将那串jwt.sign()生成的token复制到这里位置: 

         复制如下:可以看到下面的签名无效,那是缺少了什么?

         确实的就是解析的密钥了,代码中采用的是对称加密,也就是生成和解析用到都是同一套密钥,可以在代码中看到密钥了,var secret = 'The author is lhxz' ;输入之后可以看到

        这里当然不是说你可以在官网上就能破译出来,而是需要密钥;也即是当别人拿到你的密钥之后就能轻松破译,所以保管好你的密钥,如果觉得不安全的话还可以通过非对称加密,由于内容有点多就不再多说了,后续有机会的话再来提及;

3. 通过 /checklogin 中来查看是否有已经解析的JSON返回:

 4. 捕获解析失败

        当使用express-jwt解析token字符串的时候,如客户端发送的token是无效的或者不合法的,那么会导致程序的错误影响程序的运行,那么可以通过Express错误中间件来捕获这些错误;

        以下通过捕获之后提醒用户token无效,然后重新跳转回到登录界面;

         以上内容就是本篇目的一个内容了,内容与先前讲过的一些案例进行了一个结合和使用JWT进行验证登录,案例并不涉及比较难的内容,比较适中如果感兴趣的朋友可以看看,那么在这里感谢大家的支持!

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

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

相关文章

Java笔记023-包装类、String类、字符串的特性、String类、StringBuffer类、StringBuilder类

常用类包装类包装类的分类1、针对八种基本定义相应的引用类型-包装类2、有了类的特点&#xff0c;就可以调用类中的方法基本数据类型包装类booleanBooleancharCharacterbyteByteshortShortintIntegerlongLongfloatFloatdoubleDouble包装类和基本数据的转换演示包装类和基本数据…

LInux目录结构

文章目录Linux的目录结构Linux的目录结构Linux路径的描述方式目录各功能介绍HOME目录和工作目录Linux的目录结构 Linux的目录结构 Linux的目录结构是一个树型结构。 Windows 系统可以拥有多个盘符, 如 C盘、D盘、E盘 Linux没有盘符这个概念, 只有一个根目录 /, 所有文件都在…

【UE4 第一人称射击游戏】37-拾取副武器“M4A1”

上一篇&#xff1a;【UE4 第一人称射击游戏】36-切换武器时改变UI本篇效果&#xff1a;在拾取副武器“M4A1”前&#xff0c;点击键盘2键是无法切换武器的&#xff0c;当拾取武器后&#xff0c;点击键盘2键可以切换武器&#xff08;目前仅是右下角的图标和文字实现了切换&#x…

VBA小模板,一个不放回的抽奖用的例子

1 问题 一个不放回的抽奖用VBA怎么写&#xff0c;下面用一个类似对对碰/ 翻牌子的游戏&#xff08;抽到的奖励不放回&#xff0c;可抽的东西越来越少&#xff09;来举例说明 1.1 首先要回顾下几个经典的随机模型 古典概型&#xff0c;重点就是每次抽奖的各个奖品&#xff0c;概…

宇视门禁一体机接线图

宇视门禁一体机接线图宇视门禁一体机带反馈信号电磁锁接线图门禁的GND线通用&#xff0c;可以连到同一根线上&#xff0c;也可以分开连简单整理如图一体机线颜色和功能对应表颜色线路绿色RS485_A粉色RS485_B黑色GND蓝色WIEGAND_OUT_D0白色WIEGAND_OUT_D1灰色WIEGAND_IN_D0棕色W…

测试面试真题|工作2年,从小厂到大厂,薪资翻倍是怎样的体验?

最近&#xff0c;霍格沃兹测试学院学员 C 同学成功拿下某互联网大厂年薪 30W 测试开发岗位 Offer&#xff0c;顺利完成从手工测试工程师到测试开发的逆袭&#xff0c;薪资翻倍&#xff08;涨幅 100%&#xff09;&#xff0c;并获得了学院颁发的优秀学员奖学金。C 同学工作刚满 …

【3D目标检测】Delving into Localization Errors for Monocular 3D Object Detection

目录概述细节错误分析概述 本文是基于单目图像的3D目标检测方法。 【2021】【MonoDLE】 研究的问题: 核心问题&#xff1a;如何提高基于单目图像的3D目标检测的效果。作者量化了每个子任务的整体影响&#xff0c;观察到以下现象 观察一&#xff1a;定位误差是制约目标检测性…

变异凯撒题解

题目变异凯撒&#xff0c;说明没有使用一般的凯撒加密看到一个密码&#xff0c;我们可以找一下规律首先密文不完全是字母&#xff0c;但是经典凯撒加密的密文一定都是字母&#xff0c;说明这个题目可能是ASCLL码表偏移&#xff0c;而不是字母表偏移经典凯撒加密是字母和字母的偏…

SSM纯注解后台代码整合(Spring+SpringMvc+Mybatis)

SSM后台整合&#xff08;SpringSpringMvcMybtis事务Rest风格统一结果封装统一异常处理拦截器&#xff09; 文章目录1 基础环境搭建1.1 建表1.2 创建web项目1.3 导入依赖坐标&#xff08;pom.xml&#xff09;1.4 包路径的创建1.5 在pojo包下编写book实体类1.6 在webapp包下导入静…

很多人还不知道中视频计划手机上发布多端横竖屏视频的方法

如果说你刚开始接触中视频&#xff0c;你必须要学会的小知识。 横屏视频是16&#xff1b;9的视频&#xff0c;一般是手机横向拍摄的视频。 上传这样的视频有两种方法。第一种是需要用到电脑&#xff0c;第二种就是我今天要分享的这种&#xff0c;没有电脑&#xff0c;我们用手…

测试新人入职第一天都做什么?

测试入职第一天都做什么&#xff1f; 大家都知道&#xff0c;入职一家新公司就是一个新的起点&#xff0c;新的开始。不管在之前公司干了多久&#xff0c;还是第一次踏入社会进入企业上班&#xff0c;都需要遵守新公司的规则以及规章制度。不管企业的规章制度是什么&#xff0…

前端提交信息规范 commit规范 commitlint husky commitizen

前端提交规范 约定式提交约定式提交安装commitizen 及其适配器husky commitlint 提交校验至此恭喜你已经配置好提交校验了&#xff0c;快去试试吧技术同学开发中有没有出现 &#xff1a; 因某种原因当需要回滚&#xff0c;这时候一看之前提交的massage真的乌烟瘴气 无法分辨回…

使用ResNet50实现CIFAR100数据集的训练

如果对你有用的话&#xff0c;希望能够点赞支持一下&#xff0c;这样我就能有更多的动力更新更多的学习笔记了。&#x1f604;&#x1f604; 使用ResNet进行CIFAR-10数据集进行测试&#xff0c;这里使用的是将CIFAR-10数据集的分辨率扩大到32X32&#xff0c;因为算力相关的…

蓝桥杯2019年第十届省赛C++B组

文章目录A&#xff1a;组队&#xff08;5分 √&#xff09;B&#xff1a;年号字串&#xff08;5分 √&#xff09;C: 数列求值&#xff08;10分 √&#xff09;D: 数的分解&#xff08;10分 &#xff09;F: 特别数的和&#xff08;15分 √&#xff09;A&#xff1a;组队&#x…

【蓝桥杯简单篇】Python组刷题日寄Part05

刷题日记&#xff1f;刷题日寄&#xff01; 萌新备战蓝桥杯python组 &#x1f339; 发现有需要纠正的地方&#xff0c;烦请指正&#xff01; &#x1f680; 欢迎小伙伴们的三连关注&#xff01; 往期系列&#xff1a; 【蓝桥杯简单篇】Python组刷题日寄Part01 【蓝桥杯简单篇】…

Oracle Mysql审计日志等保测评

mysql oracle的审计日志 mysql的审计日志说是有两种方法&#xff0c;一种是需要安装插件模式的审计&#xff0c;一种直接开一个参数 1.安装插件模式 一、 mysql 日志 配置永久配置 &#xff1a; 保存时间及大小 https://blog.csdn.net/m0_51197424/article/details/12432840…

设计模式(二)----软件设计原则

在软件开发中&#xff0c;为了提高软件系统的可维护性和可复用性&#xff0c;增加软件的可扩展性和灵活性&#xff0c;要尽量根据7条原则来开发程序&#xff0c;从而提高软件开发效率、节约软件开发成本和维护成本。 1、单一职责原则 ( 核心&#xff1a;尽量保证类&#xff0…

毫米波雷达和视觉融合的学习路线

了解各个传感器的成像原理&#xff0c;知其所以然&#xff0c;同时了解每种传感器的对比及优缺点&#xff0c;为什么要用这几种融合&#xff0c;可以通过去看一些德州仪器的雷达原理视频&#xff08;b站&#xff09;&#xff0c;雷达工作手册等。先广而后深&#xff1a;了解经典…

C#-WPF介绍-创建项目-添加按钮等及其事件处理、属性设置

微软官网指导链接&#xff1a;适用于 .NET 5 的 Windows Presentation Foundation 文档 | Microsoft Learn WPF框架介绍&#xff1a;Windows Presentation Foundation 简介 - WPF .NET | Microsoft Learn WPF介绍 WPF&#xff08;Windows Presentation Foundation&#xff09…

python3在window上运行或安装模块各种问题

1. 在window上运行celery各种奇怪的问题 如出现错误&#xff1a; ValueError: not enough values to unpack (expected 3, got 0) 请先安装如下模块 pip install eventlet 启动时&#xff0c;带上改模块&#xff0c;指定为运行参数 celery -A tasks worker --loglevelinfo -P …