springboot实战学习(7)(JWT令牌的组成、JWT令牌的使用与验证)

接着上篇博客的学习。上篇博客是在基本完成用户模块的注册接口的开发以及注册时的参数合法性校验的基础上,基本完成用户模块的登录接口的主逻辑以及提到了问题:"用户未登录,需要通过登录,获取到令牌进行登录认证,才能使用其他功能的接口"。具体往回看了解的链接如下。springboot实战学习(6)(用户模块的登录认证)(初识令牌)(JWT)-CSDN博客文章浏览阅读2次。本篇博客是在处理用户模块中登录认证时遇到需要解决的问题。因为未登录时,需要做到无法访问和使用其他功能的接口。也就提到了令牌的作用以及满足令牌的规范"JWT"。具体的学习下篇博客进行学习...https://blog.csdn.net/m0_74363339/article/details/142365524?spm=1001.2014.3001.5502

接下来就去认真了解和学习Web登录认证中常用的令牌规范——>"JWT"。

目录

一、JWT(令牌规范)

(1)基本介绍

(2)基本组成

(I)解释上方图片(JWT令牌字符串)

(II)总结组成

二、程序中使用JWT令牌 

(1)回顾与思考

三、JWT令牌的生成

(1)JWT令牌示范

(1)如何生成

(2)如何使用生成"JWT令牌"工具

(I)第一步。导入工具的坐标(依赖)

(II)第二步。调用API,生成令牌。

(III)生成"JWT令牌"的代码不需要去记忆

(3)IDEA中写单元测试的方法测试生成JWT令牌

四、JWT令牌的验证

(1)DEA中写单元测试的方法测试"JWT令牌"的验证

(2)测试因篡改"JWT令牌"导致验证失败的几种情况

(I)篡改JWP令牌"头部部分"进行验证。

​编辑

(II)篡改JWP令牌中间"载荷部分"进行验证。

(III)篡改JWP令牌尾部"数字签名"(篡改密钥)进行验证。

(3)处理因篡改JWT令牌的数据导致的异常

(I)如果篡改了头部和载荷部分的数据,那么验证失败。

(II)如果篡改了密钥数据,那么验证失败。

(III)如果超过设定的Token令牌过期时间,那么验证失败。

(4)关于"JWT令牌"验证的注意事项

五、总结

(1)JWT令牌的组成

(2)JWT令牌的使用

(3)尾言


一、JWT(令牌规范)

(1)基本介绍
  • JWT的全称:JSON Web Token
JSON Web Tokens - jwt.ioJSON Web Token (JWT) is a compact URL-safe means of representing claims to be transferred between two parties. The claims in a JWT are encoded as a JSON object that is digitally signed using JSON Web Signature (JWS).icon-default.png?t=O83Ahttps://jwt.io/

也就是用于Web领域的基于JSON格式的令牌

  • 定义了一种简洁的、自包含的格式,用于通信双方以json数据格式安全的传输信息。

(JSON是一种文本数据格式,来源于JavaScript的对象语法。

(2)基本组成

(I)解释上方图片(JWT令牌字符串)
  • 上面展示的它是前后端交互时传输的字符串。而这个字符串是由JSON格式的字符串编码得来的字符串。可以看到上面字符串有两个小".",它就是把这整个字符串分为三个部分。而"分割"的每一个小串,对应着Token令牌的一部分。
  • 第一部分是头。它是由JSON字符串编码得来的。这个部分的字符串会记录两个信息。第一个是"alg"(它是加密算法,防篡改),而"type"(是JWT)。
  • 第二部分是"有效载荷"。它是也是一段字符串。而在这段字符串中,他会存放我们的业务数据。比如存放用户的id、用户的username等等。这段字符串编码后,也会得到上面Token令牌里面的这一段。 

  • 而对应的JSON格式的字符串,是如何转换为上面Token令牌中展示的这一段"特殊长的字符串"呢?在JWT中会借助于"base64"这种编码方式完成。而"base64"可以将任意数据转换成64个可打印字符('a'-'z'、'A'-'Z'、'0'-'9'等等)。这些64个可打印字符最重要的特点就是:"通用",在任意场景都可以被支持。
  • 将JSON格式的字符串转换为64个可打印的字符串,原因是为了提供Token令牌的实用性。记得"base64"仅仅是一种编码方式,而不是加密。因此记得在Token令牌的第二部分"有效载荷",一定注意不要放私密数据(比如用户密码等),不然不安全。


  • 最后一部分叫做"数字签名"。它是将第一部分以及第二部分,借助于密钥和加密算法,通过加密得来的。而这里的加密算法,是通过头部的"alg"来制定的。密钥可以在程序中单独配置。
  • 有了这个数字签名,就可以防篡改,确保Token是安全的。因为将来即使篡改了第一和第二部分,但第三部分是不能篡改的,因为是加密后的字符串。将来JWT再去解析Token令牌时,通过解密第三部分,得到"头部"与"载荷",再拿到解密的内容与用户传递的内容进行比对,如果不一样,就不让访问。
(II)总结组成

二、程序中使用JWT令牌 

(1)回顾与思考
  • 回到之前的所完成用户模块的注册接口与登录接口的主逻辑。

springboot实战学习笔记(5)(用户登录接口的主逻辑)-CSDN博客

  • 现在需要在用户登录之后生成一个"JWT令牌",生成了之后还需要把"JWT令牌"响应给浏览器。
  • 将来浏览器再去访问服务器上的其它资料时,会携带这个令牌访问。这时服务器就能够得到这个令牌,并且还需要去验证这个令牌的合法性。如果令牌合法、没有被篡改,就正常提供服务,反之。
  • 需要学习如何生成令牌?如何验证令牌?

三、JWT令牌的生成

(1)JWT令牌示范

(1)如何生成
  • 可以自己手写,毕竟JWT是一个令牌的规范写法。而是规范,大家都可以实现的。
  • 有人提供了生成"JWT令牌"的工具,所以可以直接使用这些工具即可。
(2)如何使用生成"JWT令牌"工具
(I)第一步。导入工具的坐标(依赖)
  • 引入的是java-jwt

  • 引入坐标时,报错,记得尝试刷新一个Maven

  • 因为我们当前写的"生成令牌"或者"验证令牌"代码,它仅仅是一个测试的代码。所以需要把它写到单元测试里面。所以还要引入单元测试的坐标

  • springboot为了更方便的测试spring程序,提供了springboot整合单元测试的一个起步依赖。

  • 添加完毕,一定记得刷新Maven。

(II)第二步。调用API,生成令牌。
(III)生成"JWT令牌"的代码不需要去记忆
  • 因为将来在公司中使用的时候,都是使用提供好的工具类,然后直接调用即可
(3)IDEA中写单元测试的方法测试生成JWT令牌
  • 在test目录的feisi目录下,新建一个类"JwtTest"。在这个类的内部去写单元测试的代码。

  • 新建一个方法testGen(),并且需要在方法上添加一个注解@Test

  • 如果要生成令牌,就要调用JWT的API。然后先调用其create()方法。
  • 然后利用链式编程的方式来调用方法。首先调用第一个方法"withClaim()",这个方法的作用是添加"载荷"(前面讲过)。

  • 这个添加载荷的方法就是:第一值传入键的名字(name)(如这里设置为"user",那么将来这个载荷就是承载着用户相关的信息),第二个参数值放一个map集合,比如user将来肯定有"id"、"username"等等。
JWT.create()
                .withClaim("user",claims);
  • 所以接着就要创建一个Map类型的集合。指定其键是"String"类型,而值是"Object"类型的
Map<String, Object> claims = new HashMap<>();
  • 有了这个claims集合,就可以调用方法put()。如下添加。这样就提供添加"载荷"的方式,把当前用户信息添加进去了。
claims.put("id",1);
        claims.put("username","张三");
  • 接下来JWT.create().后面还可以添加几个方法。

  • .withExpiresAt()。这是添加过期时间。也就是登录时获得的令牌是有登录有效期的,时间过了,就需要重新登录。将来的Token令牌是有有效期的。
  • 里面是需要一个Data对象。直接new Data()。但是这个是当前的时间,所以还需要通过System提供的获取当前毫秒值的方法,再重新new一个Data对象。往后延迟指定一段时间。
  • 当前毫秒值+1000*60*60*12(也就是延后12个小时)
JWT.create()
                .withClaim("user",claims)
                .withExpiresAt(new Date(System.currentTimeMillis()+1000*60*60*12));

  • sign()方法。"sign"是签名的意思。也就是如上面说的数字签名,加密用的。方法参数需要指定一个加密算法。这里选择HMAC256()这个算法。
  • 在指定算法的时候,需要指定一个密钥。这个是由自己定就行,就是一个字符串。但是它是加密的密钥,所以不要泄露,不然不能防篡改,保证安全。
.sign(Algorithm.HMAC256("feisi"));//指定算法,配置密钥

  • 这几个方法一旦调用,我们的Token令牌就能生成。所以就要去接收一下Token。
package com.feisi;

import com.auth0.jwt.JWT;
import com.auth0.jwt.algorithms.Algorithm;
import org.junit.jupiter.api.Test;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;


public class JwtTest {
    //生成JWT令牌的方法
    @Test
    public void testGen(){
        Map<String, Object> claims = new HashMap<>();
        claims.put("id",1);
        claims.put("username","张三");
        //生成JWT代码
        String token = JWT.create()
                .withClaim("user",claims) //添加载荷
                .withExpiresAt(new Date(System.currentTimeMillis()+1000*60*60*12)) //添加过期时间
                .sign(Algorithm.HMAC256("feisi"));//指定算法,配置密钥
        //打印输出到控制台,查看生成的token令牌
        System.out.println(token);
    }
}

  • 最后运行一下这个测试类的方法。这样"JWT令牌"的生成就完成了。

四、JWT令牌的验证

(1)DEA中写单元测试的方法测试"JWT令牌"的验证
  • 首先这一部分的代码也不需要去背或者记忆。
  • 接着上面,在"testGen()"方法下添加一个方法"testParse()"。
  • 也是一样记得添加单元测试的注解@Test


  • 接着定义一个字符串"token",模拟存储用户传递给浏览器的token令牌。
  • 而这个token的值就用上面控制台打印的token令牌字符串就行。
//验证JWT令牌的方法
    @Test
    public void testParse(){
        //定义字符串,模拟用户传递给浏览器的token令牌
        //这个token就用上面生成的token令牌字符串就行
        String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9"
                +".eyJ1c2VyIjp7ImlkIjoxLCJ1c2VybmFtZSI6IuW8oOS4iSJ9LCJleHAiOjE3MjcwMzg2MDl9"
                +".LgfVNY-OAkjAps8yQXDkKyCIRbWw5jNQiNZwwbMf2F4";
    }

  • 接着开始提供验证了。去提供调用JWT这个类里面的一个静态方法"require()"。这是申请一个JWT的验证器。
  • 而这个方法里面的参数需要传递一个算法。之前加密用的算法,解密也要同样用一样的算法。直接复制过来。
  • 然后再调用一个".build()"方法去生成验证器。再用一个变量"jwtVerifier"给他存起来。
JWTVerifier jwtVerifier = JWT.require(Algorithm.HMAC256("feisi")).build();

  • 有了这个变量之后,就可以调用验证器的方法,去验证这个token令牌字符串。
  • 调用方法".verify()",把之前控制台的token传递给它。


  • 它可以去解析这个token令牌。然后生成一个解析后的JWT对象。
DecodedJWT decodedJWT = jwtVerifier.verify(token); //验证token,生成一个解析后的JWT对象
  • 如果能正常的解析成功之后。那么就意味着可以从变量"decodedJWT"里面获取到当前的"头部"或者"载荷"以及"数字签名"等等。
  • 则调用它的一个方法:"GetClaims()",而它会得到所有的"载荷"。用Map对象的变量去接收一下它。
Map<String, Claim> claims = decodedJWT.getClaims();
  • 然后我们指定获取键名(name)为"user"的载荷。并且把得到的结果输出到控制台里面。
package com.feisi;

import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.interfaces.Claim;
import com.auth0.jwt.interfaces.DecodedJWT;
import org.junit.jupiter.api.Test;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;


public class JwtTest {

    //生成JWT令牌的方法
    @Test
    public void testGen(){
        Map<String, Object> claims = new HashMap<>();
        claims.put("id",1);
        claims.put("username","张三");
        //生成JWT代码
        String token = JWT.create()
                .withClaim("user",claims) //添加载荷
                .withExpiresAt(new Date(System.currentTimeMillis()+1000*60*60*12)) //添加过期时间
                .sign(Algorithm.HMAC256("feisi"));//指定算法,配置密钥
        //打印输出到控制台,查看生成的token令牌
        System.out.println(token);
    }
    //验证JWT令牌的方法
    @Test
    public void testParse(){
        //定义字符串,模拟用户传递给浏览器的token令牌
        //这个token就用上面生成的token令牌字符串就行
        String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9"
                +".eyJ1c2VyIjp7ImlkIjoxLCJ1c2VybmFtZSI6IuW8oOS4iSJ9LCJleHAiOjE3MjcwMzg2MDl9"
                +".LgfVNY-OAkjAps8yQXDkKyCIRbWw5jNQiNZwwbMf2F4";
        JWTVerifier jwtVerifier = JWT.require(Algorithm.HMAC256("feisi")).build();
        DecodedJWT decodedJWT = jwtVerifier.verify(token); //验证token,生成一个解析后的JWT对象
        Map<String, Claim> claims = decodedJWT.getClaims();
        System.out.println(claims.get("user"));

    }
}

  • 得到控制台的正常输出,如:"id,1"、"username,"张三""等等就解析成功了!
  • 正常的解析成功如下。


(2)测试因篡改"JWT令牌"导致验证失败的几种情况
(I)篡改JWP令牌"头部部分"进行验证。

(II)篡改JWP令牌中间"载荷部分"进行验证。

  • 所以我们的JWT令牌是具体放篡改的功能的。

(III)篡改JWP令牌尾部"数字签名"(篡改密钥)进行验证。
  • 篡改了原来设定的密钥"feisi"改成"fesi"。


(3)处理因篡改JWT令牌的数据导致的异常
(I)如果篡改了头部和载荷部分的数据,那么验证失败。
(II)如果篡改了密钥数据,那么验证失败。
(III)如果超过设定的Token令牌过期时间,那么验证失败。

Token过期

  • 例如如下情况:报错提示"这个Token令牌"已经过期。

(4)关于"JWT令牌"验证的注意事项

五、总结

(1)JWT令牌的组成

  • "载荷"这一块要注意。不要存放一些私密信息,因为"base64"算法不是一个加密算法,它是公开的,每个人都能使用
  • 通过密钥与加密算法去验证Token令牌的合法性
(2)JWT令牌的使用

(借助工具:"JAVA-JWT")

(3)尾言

下篇博客就要开始继续完成用户登录认证的接口开发了!也就是把令牌的生成与验证加入到登录功能中

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Linux 安装redis主从模式+哨兵模式3台节点

下载 https://download.redis.io/releases/ 解压 tar -zxvf redis-7.2.4.tar.gz -C /opt chmod 777 -R /opt/redis-7.2.4/安装 # 编译 make # 安装&#xff0c; 一定是大写PREFIX make PREFIX/opt/redis-7.2.4/redis/ install配置为系统服务 cd /etc/systemd/system/主服务…

一文上手SpringSecuirty【六】

自定义认证流程完成之后,前端收到了后端生成的token,那么在之后的所有请求当前,都必须携带token.作为服务器来说,得验证这个token,是否合法. 一、验证token是否合法 1.1 OncePerRequestFilter过滤器 OncePerRequestFilter是 Spring 框架中的一个过滤器&#xff0c;用于确保在…

基于nodejs+vue的校园二手物品交易系统

作者&#xff1a;计算机学姐 开发技术&#xff1a;SpringBoot、SSM、Vue、MySQL、JSP、ElementUI、Python、小程序等&#xff0c;“文末源码”。 专栏推荐&#xff1a;前后端分离项目源码、SpringBoot项目源码、Vue项目源码、SSM项目源码 精品专栏&#xff1a;Java精选实战项目…

Rust 语言开发 ESP32C3 并在 Wokwi 电子模拟器上运行(esp-hal 非标准库、LCD1602、I2C)

文章目录 esp-rs 简介GithubRust 包仓库Wokwi 电子模拟器开发环境Rust 环境esp-rs 环境创建 ESP32C3 项目项目结构编译项目命令运行模拟器ESP32C3 烧录 esp-rs 简介 esp-rs 是一个专注于为 Espressif 系列芯片&#xff08;如 ESP32、ESP32-S2、ESP32-C3 等&#xff09;提供 Ru…

如何在 Three.js 场景中创建可点击展开的标签

在复杂的可视化场景中&#xff0c;经常需要为 3D 对象添加可交互的标签&#xff0c;以便用户点击时可以查看详细信息。这篇文章将通过一个简单的案例展示&#xff0c;如何在 Three.js 中为对象创建可点击的标签&#xff0c;点击标签可以展开详细信息&#xff0c;再次点击可以关…

论文复现:考虑电网交互的风电、光伏与电池互补调度运行(MATLAB-Yalmip-Cplex全代码)

论文复现:考虑电网交互的风电、光伏与电池储能互补调度运行(MATLAB-Yalmip-Cplex全代码) 针对风电、光伏与电化学储能电站互补运行的问题,已有大量通过启发式算法寻优的案例,但工程上更注重实用性和普适性。Yalmip工具箱则是一种基于MATLAB平台的优化软件工具箱,被广泛应用…

基于单片机语音智能导盲仪仿真设计

文章目录 前言资料获取设计介绍设计程序具体实现截图设计获取 前言 &#x1f497;博主介绍&#xff1a;✌全网粉丝10W,CSDN特邀作者、博客专家、CSDN新星计划导师&#xff0c;一名热衷于单片机技术探索与分享的博主、专注于 精通51/STM32/MSP430/AVR等单片机设计 主要对象是咱们…

【Python】探索 Graphene:Python 中的 GraphQL 框架

人们常说挣多挣少都要开心&#xff0c;这话我相信&#xff0c;但是请问挣少了怎么开心&#xff1f; 随着现代 Web 应用对数据交互需求的不断增长&#xff0c;GraphQL 作为一种数据查询和操作语言&#xff0c;越来越受到开发者的青睐。Graphene 是 Python 语言中实现 GraphQL 的…

基于SpringBoot+Vue3的在线报名系统

一、项目介绍 1.1 项目介绍 本项目为一个报名系统&#xff0c;实现了基本的报名流程&#xff0c;功能完善&#xff0c;前后端皆有个人独立开发&#xff0c;功能相对不是特别难&#xff0c;但该有的功能还是都已经实现。 1.2 技术架构 主要技术栈&#xff1a; SpringBoot2 …

WebRTC中的维纳滤波器实现详解:基于决策导向的SNR估计

目录 1. 维纳滤波器的基本原理2. WebRTC中的维纳滤波器实现3. 代码逐步剖析4. 总结 在WebRTC的噪声抑制模块中&#xff0c;维纳滤波器&#xff08;Wiener Filter&#xff09;是一种非常常见且重要的滤波器&#xff0c;用于提高语音信号的清晰度并抑制背景噪声。本文将详细解释维…

erlang学习:Linux命令学习6

for循环学习 打印九九乘法表 for i in {1..9};do %%取1-9for j in $(seq 1 $i);do %%取1-iecho -n "$j*$i$((i*j)) " %%进行九九乘法表打印doneecho done尝试了很多次报错是因为后面的换行符不对&#xff0c;window系统中的换行符与linux对不上&#xff0c;因…

AI芯片WT2605C赋能厨房家电,在线对话操控,引领智能烹饪新体验:尽享高效便捷生活

在智能家居的蓬勃发展中&#xff0c;智能厨电作为连接科技与生活的桥梁&#xff0c;正逐步渗透到每一个现代家庭的厨房中。蒸烤箱作为智能厨电的代表&#xff0c;以其丰富的功能和高效的性能&#xff0c;满足了人们对美食的多样化追求。然而&#xff0c;面对众多复杂的操作功能…

OpenHarmony(鸿蒙南向)——平台驱动开发【MIPI DSI】

往期知识点记录&#xff1a; 鸿蒙&#xff08;HarmonyOS&#xff09;应用层开发&#xff08;北向&#xff09;知识点汇总 鸿蒙&#xff08;OpenHarmony&#xff09;南向开发保姆级知识点汇总~ 持续更新中…… 概述 功能简介 DSI&#xff08;Display Serial Interface&#x…

小阿轩yx-案例:代码管理系统简介与部署

小阿轩yx-案例&#xff1a;代码管理系统简介与部署 前言 开发一个项目时&#xff0c;如果只有几十行代码或几百行代码时维护还算简单&#xff0c;但是代码数量达到一定程度或两三个人共同开发一个项目时&#xff0c;就很容易会出现代码混乱、冲突、排错难等问题。代码编写完成…

【软件测试】如何设计测试用例? 设计测试用例常用的方法.

目录 一.什么是测试用例?二.总体设计测试用例的万能公式.2.1 功能性能界面兼容易用安全2.2 弱网测试2.3 安装卸载测试. 三. 常用设计具体测试用例的方法3.1 等价类3.2 边界值3.3 正交法3.3.1 正交表3.3.2 如何设计正交表,并根据正交表编写测试用例 3.4 判定表法3.4.1 根据判定…

828华为云征文 | 解锁高效项目管理,Zentao在华为云Flexusx容器化部署与应用指南

前言 在当今快速迭代的商业环境中&#xff0c;高效且灵活的项目管理成为企业竞争力的关键。华为云Flexusx实例&#xff0c;以其灵活的vCPU内存配比、热变配功能及按需计费模式&#xff0c;为项目管理软件如Zentao的部署提供了理想平台。Flexusx实例采用按需计费的灵活定价模式&…

Ansible流程控制-条件_循环_错误处理_包含导入_块异常处理

文章目录 Ansible流程控制介绍1. 条件判断2. 循环3. 循环控制4. 错误处理5. 包含和导入6. 块和异常处理7. 角色的流程控制*include_tasks、import_tasks_include之间的区别 条件语句再细说且、或、非、是模糊条件when指令的详细使用方法 循环语句再细说如何使用使用item变量结合…

甄选范文“论软件需求管理”,软考高级论文,系统架构设计师论文

论文真题 软件需求管理是一个对系统需求变更了解和控制的过程。需求管理过程与需求开发过程相互关联,初始需求导出的同时就要形成需求管理规划,一旦启动了软件开发过程,需求管理活动就紧密相伴。 需求管理过程中主要包含变更控制、版本控制、需求跟踪和需求状态跟踪等4项活…

???Ansible-使用roles

文章目录 一、Ansible的内置的或官方推荐创建的目录及文件介绍roles目录解释1、roles/自定义角色名目录下2、roles/自定义角色名目录/tasks目录下3、roles/自定义角色名目录/handlers目录下4、roles/自定义角色名目录/templates目录下5、roles/自定义项目名目录/files目录下6、…

SSM超市售卖管理系统-计算机毕业设计源码23976

目 录 摘要 Abstract 1 绪论 1.1研究的背景和意义 1.2研究内容 1.3论文结构与章节安排 2 开发技术介绍 2.1 SSM框架 2.2 MySQL数据库 3 超市售卖管理系统系统分析 3.1 可行性分析 3.2 系统流程分析 3.2.1 数据流程 3.3.2 业务流程 3.3 系统功能分析 3.3.1 功…