理解Web登录机制:会话管理与跟踪技术解析(二)-JWT令牌

JWT令牌是一种用于安全地在各方之间传递信息的开放标准,它不仅能够验证用户的身份,还可以安全地传递有用的信息。由于其结构简单且基于JSON,JWT可以在不同的系统、平台和语言间无缝传递,成为现代Web开发中不可或缺的一部分。

文章目录

前言

JWT令牌

 介绍

生成和校验

登录下发令牌

总结


前言

JWT令牌是一种用于安全地在各方之间传递信息的开放标准,它不仅能够验证用户的身份,还可以安全地传递有用的信息。由于其结构简单且基于JSON,JWT可以在不同的系统、平台和语言间无缝传递,成为现代Web开发中不可或缺的一部分。


提示:以下是本篇文章正文内容,下面案例可供参考

JWT令牌

 介绍

JWT全称:JSON Web Token (官网:https://jwt.io/)

定义了一种简洁的、自包含的格式,用于在通信双方以json数据格式安全的传输信息。由于数字
签名的存在,这些信息是可靠的。

简洁:是指jwt就是一个简单的字符串。可以在请求参数或者是请求头当中直接传递。
自包含:指的是jwt令牌,看似是一个随机的字符串,但是我们是可以根据自身的需求在jwt
令牌中存储自定义的数据内容。如:可以直接在jwt令牌中存储用户的相关信息。
简单来讲,jwt就是将原始的json数据格式进行了安全的封装,这样就可以直接基于jwt在
通信双方安全的进行信息传输了。

JWT的组成: (JWT令牌由三个部分组成,三个部分之间使用英文的点来分割)

  • 第一部分:Header(头), 记录令牌类型、签名算法等。 例如:{"alg":"HS256","type":"JWT"}
  • 第二部分:Payload(有效载荷),携带一些自定义信息、默认信息等。 例如:{"id":"1","username":"Tom"}
  • 第三部分:Signature(签名),防止Token被篡改、确保安全性。将header、payload,并加入指定秘钥,通过指定签名算法计算而来。

签名的目的就是为了防jwt令牌被篡改,而正是因为jwt令牌最后一个部分数字签名的存在,
所以整个jwt 令牌是非常安全可靠的。一旦jwt令牌当中任何一个部分、任何一个字符被篡
改了,整个令牌在校验的时候都会失败,所以它是非常安全可靠的。

JWT是如何将原始的JSON格式数据,转变为字符串的呢?

其实在生成JWT令牌时,会对JSON格式的数据进行一次编码:进行base64编码
Base64:是一种基于64个可打印的字符来表示二进制数据的编码方式。既然能编码,那也就意味着也能解码。所使用的64个字符分别是A到Z、a到z、 0- 9,一个加号,一个斜杠,加起来就是64个字符。任何数据经过base64编码之后,最终就会通过这64个字符来表示。当然还有一个符号,那就是等号。等号它是一个补位的符号
需要注意的是Base64是编码方式,而不是加密方式。

JWT令牌最典型的应用场景就是登录认证:
1. 在浏览器发起请求来执行登录操作,此时会访问登录的接口,如果登录成功之后,我们需要生成
一个jwt令牌,将生成的 jwt令牌返回给前端。
2. 前端拿到jwt令牌之后,会将jwt令牌存储起来。在后续的每一次请求中都会将jwt令牌携带到服
务端。
3. 服务端统一拦截请求之后,先来判断一下这次请求有没有把令牌带过来,如果没有带过来,直接
拒绝访问,如果带过来了,还要校验一下令牌是否是有效。如果有效,就直接放行进行请求的处
理。

在JWT登录认证的场景中我们发现,整个流程当中涉及到两步操作:
1. 在登录成功之后,要生成令牌。
2. 每一次请求当中,要接收令牌并对令牌进行校验。

生成和校验

简单介绍了JWT令牌以及JWT令牌的组成之后,接下来我们就来学习基于Java代码如何生成和校验JWT令牌。
首先我们先来实现JWT令牌的生成。要想使用JWT令牌,需要先引入JWT的依赖:

<!-- JWT依赖-->
<dependency><groupId>io.jsonwebtoken</groupId><artifactId>jjwt</artifactId><version>0.9.1</version>
</dependency>

在引入完JWT来赖后,就可以调用工具包中提供的API来完成JWT令牌的生成和校验
工具类:Jwts

 生成JWT代码实现:

@Test
public void genJwt(){Map<String,Object> claims = new HashMap<>();claims.put("id",1);claims.put("username","Tom");String jwt = Jwts.builder().setClaims(claims) //自定义内容(载荷) .signWith(SignatureAlgorithm.HS256, "itheima") //签名算法.setExpiration(new Date(System.currentTimeMillis() +24*3600*1000)) //有效期.compact();System.out.println(jwt);
}

运行测试方法:
 

eyJhbGciOiJIUzI1NiJ9.eyJpZCI6MSwiZXhwIjoxNjcyNzI5NzMwfQ.fHi0Ub8npbyt71
UqLXDdLyipptLgxBUg_mSuGJtXtBk

输出的结果就是生成的JWT令牌,,通过英文的点分割对三个部分进行分割,我们可以将生成的令牌复制一下,然后打开JWT的官网,将生成的令牌直接放在Encoded位置,此时就会自动的将令牌解析来。

第一部分解析出来,看到JSON格式的原始数据,所使用的签名算法为HS256。
第二个部分是我们自定义的数据,之前我们自定义的数据就是id,还有一个exp代表的是我们所设置的过期时间。
由于前两个部分是base64编码,所以是可以直接解码出来。但最后一个部分并不是base64编
码,是经过签名算法计算出来的,所以最后一个部分是不会解析的。

实现了JWT令牌的生成,下面我们接着使用Java代码来校验JWT令牌(解析生成的令牌):

@Test
public void parseJwt(){Claims claims = Jwts.parser().setSigningKey("itheima")//指定签名密钥(必须保证和生成令牌时使用相同的签名密钥).parseClaimsJws("eyJhbGciOiJIUzI1NiJ9.eyJpZCI6MSwiZXhwIjoxNjcyNzI5NzMwfQ.fHi0Ub8npbyt71UqLXDdLyipptLgxBUg_mSuGJtXtBk").getBody();System.out.println(claims);
}

运行测试方法:

{id=1, exp=1672729730}

令牌解析后,我们可以看到id和过期时间,如果在解析的过程当中没有报错,就说明解析成功了。

下面我们做一个测试:把令牌header中的数字9变为8,运行测试方法后发现报错:

原header: eyJhbGciOiJIUzI1NiJ9
修改为: eyJhbGciOiJIUzI1NiJ8

结论:篡改令牌中的任何一个字符,在对令牌进行解析时都会报错,所以JWT令牌是非常安全可靠的。
我们继续测试:修改生成令牌的时指定的过期时间,修改为1分钟

@Test
public void genJwt(){Map<String,Object> claims = new HashMap<>();claims.put(“id”,1);claims.put(“username”,“Tom”);String jwt = Jwts.builder().setClaims(claims) //自定义内容(载荷) .signWith(SignatureAlgorithm.HS256, “itheima”) //签名算法.setExpiration(new Date(System.currentTimeMillis() +60*1000)) //有效期60秒.compact();System.out.println(jwt);//输出结果:eyJhbGciOiJIUzI1NiJ9.eyJpZCI6MSwiZXhwIjoxNjczMDA5NzU0fQ.RcVIR65AkGiax-ID6FjW60eLFH3tPTKdoK7UtE4A1ro
}@Testpublic void parseJwt(){Claims claims = Jwts.parser().setSigningKey("itheima")//指定签名密钥.parseClaimsJws("eyJhbGciOiJIUzI1NiJ9.eyJpZCI6MSwiZXhwIjoxNjczMDA5NzU0fQ.RcVIR65AkGiax-ID6FjW60eLFH3tPTKdoK7UtE4A1ro").getBody();System.out.println(claims);
}

等待1分钟之后运行测试方法发现也报错了,说明:JWT令牌过期后,令牌就失效了,解析的为非法令牌。
通过以上测试,我们在使用JWT令牌时需要注意:

  • JWT校验时使用的签名秘钥,必须和生成JWT令牌时使用的秘钥是配套的。
  • 如果JWT令牌解析校验时报错,则说明 JWT令牌被篡改 或 失效了,令牌非法。

登录下发令牌

JWT令牌的生成和校验的基本操作我们已经学习完了,接下来我们就需要在案例当中通过JWT令牌技术来跟踪会话。具体的思路我们前面已经分析过了,主要就是两步:

1. 生成令牌

  • 在登录成功之后来生成一个JWT令牌,并且把这个令牌直接返回给前端

2. 校验令牌

  • 拦截前端请求,从请求中获取到令牌,对令牌进行解析校验

首先来完成:登录成功之后生成JWT令牌,并且把令牌返回给前端。

JWT令牌怎么返回给前端呢?此时我们就需要再来看一下接口文档当中关于登录接口的描述(主要看响应数据):

{
"code": 1,
"msg": "success",
"data":
"eyJhbGciOiJIUzI1NiJ9.eyJuYW1lIjoi6YeR5bq4IiwiaWQiOjEsInVzZXJuYW1l
IjoiamlueW9uZyIsImV4cCI6MTY2MjIwNzA0OH0.KkUc_CXJZJ8Dd063eImx4H9Ojf
rr6XMJ-yVzaWCVZCo"
}

备注说明

用户登录成功后,系统会自动下发JWT令牌,然后在后续的每次请求中,都需要在请求头header
中携带到服务端,请求头的名称为 token ,值为 登录时下发的JWT令牌。
如果检测到用户未登录,则会返回如下固定错误信息:

{"code": 0,"msg": "NOT_LOGIN","data": null
}

目前我们先来完成令牌的生成和令牌的下发,我们只需要生成一个令牌返回给前端就可以了。

实现步骤:
1. 引入JWT工具类

  • 在项目工程下创建com.itheima.utils包,并把提供JWT工具类复制到该包下

2. 登录完成后,调用工具类生成JWT令牌并返回

JWT工具类

public class JwtUtils {private static String signKey = "itheima";//签名密钥private static Long expire = 43200000L; //有效时间/*** 生成JWT令牌* @param claims JWT第二部分负载 payload 中存储的内容* @return*/public static String generateJwt(Map<String, Object> claims){String jwt = Jwts.builder().addClaims(claims)//自定义信息(有效载荷).signWith(SignatureAlgorithm.HS256, signKey)//签名算法(头部).setExpiration(new Date(System.currentTimeMillis() +expire))//过期时间.compact();return jwt;}/*** 解析JWT令牌* @param jwt JWT令牌* @return JWT第二部分负载 payload 中存储的内容*/public static Claims parseJWT(String jwt){Claims claims = Jwts.parser().setSigningKey(signKey)//指定签名密钥.parseClaimsJws(jwt)//指定令牌Token.getBody();return claims;}
}

登录成功,生成JWT令牌并返回

@RestController
@Slf4j
public class LoginController {//依赖业务层对象@Autowiredprivate EmpService empService;@PostMapping("/login")public Result login(@RequestBody Emp emp) {//调用业务层:登录功能Emp loginEmp = empService.login(emp);//判断:登录用户是否存在if(loginEmp !=null ){//自定义信息Map<String , Object> claims = new HashMap<>();claims.put("id", loginEmp.getId());claims.put("username",loginEmp.getUsername());claims.put("name",loginEmp.getName());//使用JWT工具类,生成身份令牌String token = JwtUtils.generateJwt(claims);return Result.success(token);}return Result.error("用户名或密码错误");}
}

打开浏览器完成前后端联调操作:利用开发者工具,抓取一下网络请求 

登录请求完成后,可以看到JWT令牌已经响应给了前端,此时前端就会将JWT令牌存储在浏览器本地。 

服务器响应的JWT令牌存储在本地浏览器哪里了呢?

  • 在当前案例中,JWT令牌存储在浏览器的本地存储空间local storage中了。 local storage是浏览器的本地存储,在移动端也是支持的。 

我们在发起一个查询部门数据的请求,此时我们可以看到在请求头中包含一个token(JWT令牌),后续的每一次请求当中,都会将这个令牌携带到服务端。


总结

通过本文的讲解,相信你已经对JWT令牌有了更加清晰的认识,并能够在实际项目中灵活应用它来增强系统的安全性和可扩展性。

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

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

相关文章

论 ONLYOFFICE:开源办公套件的深度探索

公主请阅 引言第一部分&#xff1a;ONLYOFFICE 的历史背景1.1 开源软件的崛起1.2 ONLYOFFICE 的发展历程 第二部分&#xff1a;ONLYOFFICE 的核心功能2.1 文档处理2.2 电子表格2.3 演示文稿 第三部分&#xff1a;技术架构与兼容性3.1 技术架构3.2 兼容性 第四部分&#xff1a;部…

sql报错信息将字符串转换为 uniqueidentifier 时失败

报错信息&#xff1a; [42000] [Microsoft][SQL Server Native Client 10.0][SQL Server]将字符串转换为 uniqueidentifier 时失败 出错行如下&#xff1a; 表A.SourceCode 表B.ID 出错原因&#xff1a; SourceCode是nvarchar,但ID是uniqueidentifier 数据库查询字段和类…

[复健计划][紫书]Chapter 7 暴力求解法

7.1 简单枚举 例7-1 Division uva725 输入正整数n&#xff0c;按从小到大的顺序输出所有形如abcde/fghij n的表达式&#xff0c;其中a&#xff5e;j恰好为数字0&#xff5e;9的一个排列&#xff08;可以有前导0&#xff09;&#xff0c;2≤n≤79。枚举fghij&#xff0c;验证a…

大语言模型鼻祖Transformer的模型架构和底层原理

Transformer 模型的出现标志着自然语言处理&#xff08;NLP&#xff09;技术的一次重大进步。这个概念最初是针对机器翻译等任务而提出的&#xff0c;Transformer 后来被拓展成各种形式——每种形式都针对特定的应用&#xff0c;包括原始的编码器-解码器&#xff08;encoder-de…

基于MySQL的企业专利数据高效查询与统计实现

背景 在进行产业链/产业评估工作时&#xff0c;我们需要对企业的专利进行评估&#xff0c;其中一个重要指标是统计企业每一年的专利数量。本文基于MySQL数据库&#xff0c;通过公司名称查询该公司每年的专利数&#xff0c;实现了高效的专利数据统计。 流程 项目流程概述如下&…

canfestival主站多电机对象字典配置

不要使用数组进行命名&#xff1a;无法运行PDO 使用各自命名的方式&#xff1a;

bat批量处理脚本细节研究

文章目录 bat批处理脚本&#xff08;框架&#xff09;set变量设置基本语法显示环境变量 自定义环境变量临时环境变量和永久环境变量特殊环境变量和系统默认环境变量set命令利用选项的其他应用 !与%解析变量的区别/为什么使用setlocal enabledelayedexpansion区别%的规则!使用 %…

Java 网络编程(一)—— UDP数据报套接字编程

概念 在网络编程中主要的对象有两个&#xff1a;客户端和服务器。客户端是提供请求的&#xff0c;归用户使用&#xff0c;发送的请求会被服务器接收&#xff0c;服务器根据请求做出响应&#xff0c;然后再将响应的数据包返回给客户端。 作为程序员&#xff0c;我们主要关心应…

使用C++来编写VTK项目时,就是要写自己的算法

其实&#xff0c;使用VTK可以使用很多种语言&#xff0c;比如java&#xff0c;python&#xff0c;和C。那么为什么非要使用C 呢&#xff1f;一个原因是觉得C语言处理数据比较快&#xff0c;另一个原因是需要自己写算法。通过继承polyDataAlgorithm来写自己的算法&#xff0c;很…

[ 内网渗透实战篇-2 ] 父域子域架构的搭建与安装域环境判断域控定位组策略域森林架构配置信任关系

&#x1f36c; 博主介绍 &#x1f468;‍&#x1f393; 博主介绍&#xff1a;大家好&#xff0c;我是 _PowerShell &#xff0c;很高兴认识大家~ ✨主攻领域&#xff1a;【渗透领域】【数据通信】 【通讯安全】 【web安全】【面试分析】 &#x1f389;点赞➕评论➕收藏 养成习…

FileLink跨网数据摆渡系统:打破网络隔阂,轻松实现跨网络数据传输

在数字化时代&#xff0c;跨网络、跨区域的数据传输成为了企业和个人信息流通的重大挑战。而如今&#xff0c;FileLink跨网数据摆渡系统的问世&#xff0c;彻底解决了这一难题&#xff0c;帮助用户实现快速、安全、无缝的跨网络数据传输。 1. 跨网络数据传输的痛点 随着企业信…

MySQL_聚合函数分组查询

上篇复习&#xff1a; 设计数据库时的三大范式1.第一范式&#xff0c;一行数据中每一列不可再分 关系型数据库必须要满足第一范式&#xff0c;设计表的时候&#xff0c;如果每一列都可以用SQL规定的数据类型描述&#xff0c;就天然满足第一范式. 2.第二范式&#xff0c;在第一…

【Ai教程】Ollma安装 | 0代码本地运行Qwen大模型,保姆级教程来了!

我们平时使用的ChatGPT、kimi、豆包等Ai对话工具&#xff0c;其服务器都是部署在各家公司的机房里&#xff0c;如果我们有一些隐私数据发到对话中&#xff0c;很难保证信息是否安全等问题&#xff0c;如何在保证数据安全的情况下&#xff0c;又可以使用大预言模型&#xff0c;O…

FastAPI全方位分析:优劣尽显

近年来,随着技术的飞速发展,快速构建高性能API的需求越来越强烈。Python作为一个广泛使用的编程语言,也在这一领域下涌现出了许多优秀的框架。FastAPI便是其中一颗璀璨的新星。 FastAPI以其卓越的性能和独特的功能吸引了众多开发者。本文将深入剖析FastAPI的各个方面,详细…

LongVU :Meta AI 的解锁长视频理解模型,利用自适应时空压缩技术彻底改变视频理解方式

Meta AI在视频理解方面取得了令人瞩目的里程碑式成就&#xff0c;推出了LongVU&#xff0c;这是一种开创性的模型&#xff0c;能够理解以前对人工智能系统来说具有挑战性的长视频。 研究论文 "LongVU&#xff1a;用于长视频语言理解的时空自适应压缩 "提出了一种革命…

什么是兼容性测试

兼容性测试&#xff0c;提供具有兼容性特性的云端设备&#xff08;覆盖主流品牌、SDK、分辨率&#xff09;&#xff0c;通过模拟用户行为进行真机测试。及时有效的发现应用中存在的兼容性问题。解除测试人员的双手&#xff0c;提高测试效率&#xff0c;保证产品在海量真机上的高…

IDEA:ctrl+/ 快捷键生成的注释,设置“//”开始位置

问题场景&#xff1a; IDEA中使用 ctrl/ 快捷键&#xff0c;//显示在最左边&#xff08;顶格&#xff09;&#xff0c;不美观&#xff0c;中间隔了好长的空格&#xff0c;如图&#xff1a; 解决方法: 操作步骤 File–>Sttings–>Editor–>Code Style–>Java–>…

IDEA2024下安装kubernetes插件并配置进行使用

【1】安装插件 其实2024.2.3下默认已经安装了kubernetes插件&#xff0c;如果你发现自己IDEA中没有&#xff0c;在市场里面检索并下载即可。 【2】kubernetes配置 ① 前置工作 首先你要准备一个config文件和一个kubectl.exe 。 config文件类似如下&#xff1a; apiVersi…

H7-TOOL的CAN/CANFD助手增加帧发送成功标识支持, 继续加强完善功能细节

2.27版本固件正式携带此功能&#xff0c;包括之前做的负载率检测和错误信息展示也将集成到这个版本固件中。 对于接收&#xff0c;我们可以直接看到效果&#xff0c;而发送不行&#xff0c;所以打算在发送的地方展示下发送成功标识。CAN发送不像串口&#xff0c;需要等待应答后…

CSP/信奥赛C++刷题训练:经典广搜例题(4):洛谷P1746 :离开中山路

CSP/信奥赛C刷题训练&#xff1a;经典广搜例题&#xff08;4&#xff09;&#xff1a;洛谷P1746 &#xff1a;离开中山路 题目背景 《爱与愁的故事第三弹shopping》最终章。 题目描述 爱与愁大神买完东西后&#xff0c;打算坐车离开中山路。现在爱与愁大神在 x 1 , y 1 x_1…