现代Java开发:使用jjwt实现JWT认证

前言

jjwt 库 是一个流行的 Java 库,用于创建和解析 JWT。我在学习spring security 的过程中看到了很多关于jwt的教程,其中最流行的就是使用jjwt实现jwt认证,但是教程之中依然使用的旧版的jjwt库,许多的类与方法已经标记弃用或者是已经被删除了,新版 jjwt 增加了许多新特性和改进,使得生成和验证 JWT 更加方便,故写此文以作记忆。

附上我的博客链接:现代Java开发:使用jjwt实现JWT认证

环境:

  • jjwt 0.12.5
  • jdk17+
  • Maven
  • Spring Boot 3.3.1

JWT的相关知识

JSON Web Token (JWT) 是一个开放标准(RFC 7519),它定义了一种紧凑的、自包含的方式,用于在各方之间以 JSON 对象的形式安全地传输信息。由于这些信息是经过数字签名的,因此可以被验证和信任。

JWT 的结构

JWT 由三部分组成:头部(Header)、载荷(Payload)和签名(Signature),这三部分用点 (.) 分隔。

  1. 头部(Header): 头部通常包括两部分:令牌的类型(JWT)和所使用的签名算法(如 HMAC SHA256 或 RSA)。

    {"alg": "HS256","typ": "JWT"
    }
    

    这部分会进行 Base64Url 编码,形成 JWT 的第一部分。

  2. 载荷(Payload): 载荷部分包含声明(Claims),声明是有关实体(通常是用户)和其他数据的声明。有三种类型的声明:注册声明(Registered claims)、公共声明(Public claims)和私有声明(Private claims)。

    例如:

    {"sub": "1234567890","name": "zfmx","iat": 1516239022
    }
    

    这部分也会进行 Base64Url 编码,形成 JWT 的第二部分。

  3. 签名(Signature): 签名部分用于验证消息在传输过程中是否未被篡改。需要将编码后的头部和载荷用点 (.) 连接在一起,然后使用指定的签名算法(如 HMAC SHA256)和一个密钥对其进行签名。签名的结果是 JWT 的第三部分。

编写JWT工具

引入jjwt库

首先要做的就是把jjwt引入到项目之中

<dependency><groupId>io.jsonwebtoken</groupId><artifactId>jjwt</artifactId><version>0.12.5</version>
</dependency>

写本文时最新的库应该是0.12.6,但是在引入过程中jjwt-jackson的坐标定位失败,故采用了0.12.5。

定义属性

这里有两个属性需要定义:

  • 有效时间:public static final Long JWT_TTL
  • 加密密钥:public static final String JWT_KEY

加密方法

传入subject、ttlMillis、uuid生成tooken。

hmacShaKeyFor 方法生成的密钥可以用于 JWT 的签名和验证。

currentTimeMillis 方法生成时间戳

Jwts类构建一个jwt构建器返回

 /*** 生成JWT* @param subject 用户信息 json格式* @param ttlMillis 有效时间* @param uuid 自定义uuid* @return JWT令牌*/
private static JwtBuilder getJwtBuilder(String subject, Long ttlMillis, String uuid){SecretKey secretKey = Keys.hmacShaKeyFor(JwtUtil.JWT_KEY.getBytes(StandardCharsets.UTF_8));long nowMillis = System.currentTimeMillis();    // 当前时间戳Date now = new Date(nowMillis);                 // 当前时间if(ttlMillis == null){ttlMillis = JwtUtil.JWT_TTL;}long expMillis = nowMillis + ttlMillis;     // 过期时间戳Date exp = new Date(expMillis);             // 过期时间return Jwts.builder().id(uuid).subject(subject).issuer("zfmx").issuedAt(now).signWith(secretKey).expiration(exp);
}

值得注意的是,原本的setId、setSubject等方法已经在新版jjwt中废弃,这里采用的是新版的写法

生成token

注意这里的getUUID为自己实现的生成uuid方法,重载createJWT方法来适应多种应用情况

/*** 生成JWT* @param subject 用户信息 json格式* @return JWT令牌*/
public static String createJWT(String subject){JwtBuilder jwtBuilder = getJwtBuilder(subject, null, getUUID());return jwtBuilder.compact();
}/*** 生成JWT* @param subject 用户信息 json格式* @param ttlMillis 有效时间* @return JWT令牌*/
public static String createJWT(String subject, Long ttlMillis){JwtBuilder builder = getJwtBuilder(subject, ttlMillis, getUUID());return builder.compact();
}/*** 生成JWT* @param id 自定义uuid* @param subject 用户信息 json格式* @param ttlMillis 有效时间* @return JWT令牌*/
public static String createJWT(String id,String subject,Long ttlMillis){JwtBuilder builder = getJwtBuilder(subject, ttlMillis, id);return builder.compact();
}// 生成uuid
public static String getUUID(){return UUID.randomUUID().toString().replaceAll("-","");
}

解码方法

/*** 解析JWT* @param jwt JWT令牌* @return Claims* @throws Exception 解析异常*/
public static Claims parseJWT(String jwt) throws Exception{SecretKey secretKey = Keys.hmacShaKeyFor(JwtUtil.JWT_KEY.getBytes());return Jwts.parser().verifyWith(secretKey).build().parseSignedClaims(jwt).getPayload();
}

这里的parser()\parseSignedClaims()等方法都是新版的使用方法。

浅浅测试一下吧

public static void main(String[] args) throws Exception {var token = createJWT("{'name':'zhangsan','age':18}");Claims claims = parseJWT(token);System.out.println(claims);
}

result

参考

JSON Web 令牌 - 维基百科 — JSON Web Token - Wikipedia

JJWT最新版本0.12.x使用指南,实现登陆功能,JwtUtils_jjwt 0.12-CSDN博客

jjwt/CHANGELOG.md at master · jwtk/jjwt (github.com)

SpringSecurity-从入门到精通-三更草堂 - 起跑线小言 - 博客园 (cnblogs.com)

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

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

相关文章

【Python机器学习】决策树的简单实践——预测隐形眼镜类型

使用小型数据集&#xff0c;我们就可以利用决策树学到很多知识&#xff1a;眼科医生是如何判断患者需要佩戴的镜片类型的&#xff1b;一旦理解了决策树的工作原理&#xff0c;我们甚至也可以帮助人们判断需要佩戴的镜片类型。 隐形眼镜数据集是非常著名的数据集&#xff0c;它包…

CSS常见属性详解——内边距与外边距

内边距与外边距 内边距 外边距 应用场景 在网页排版布局时&#xff0c;我们经常会希望元素与元素之间有一定的间距&#xff0c;此时我们可能会用到CSS的外边距或内边距属性&#xff0c;这两个属性都能让元素之间产生距离&#xff0c;那么他们之间有什么不同呢&#xff1f; …

富芮坤FR800X系列之按键检测模块设计

FR800X系列按键检测模块 读者对象&#xff1a; 本文档主要适用以下工程师&#xff1a; 嵌入式系统工程师 单片机软件工程师 IOT固件工程师 BLE固件工程师 文章目录 1.概要2.用户如何设计按键检测模块2.1 GPIO初始化2.2按键模块初始化2.3设计中断函数&#xff1a;2.4循环…

深入探索PHP框架:Symfony框架全面解析

1. 引言 在现代Web开发领域&#xff0c;PHP作为一种广泛使用的服务器端脚本语言&#xff0c;其框架的选择对于项目的成功至关重要。PHP框架不仅能够提高开发效率&#xff0c;还能确保代码的质量和可维护性。本文将深入探讨Symfony框架&#xff0c;这是一个功能强大且灵活的PHP…

Python学习笔记45:游戏篇之外星人入侵(六)

前言 飞船模块的功能基本已经完成。今天继续完成子弹模块的功能。 子弹模块 子弹和飞船模块&#xff0c;在游戏逻辑中有一种生成与被生成的表面关系&#xff0c;因为子弹在游戏中是由飞船发射的。但是在我们实际抽象的过程中&#xff0c;飞船与子弹并不是is的关系&#xff0…

UML通信图建模技术及应用例

新书速览|《UML 2.5基础、建模与设计实践》 在对系统的动态行为进行建模时&#xff0c;通信图常被用于按组织结构对控制流进行建模。与顺序图一样&#xff0c;一个单独的通信图只能显示一个控制流。 使用通信图建模时可以遵循如下策略&#xff1a; &#xff08;1&#xff09…

普通人这一生逆袭的唯一机会

普通人这一生逆袭的唯一机会 在人生的长河中&#xff0c;每个普通人心中都藏着一个逆袭的梦想。梦想着从平凡走向卓越&#xff0c;从底层攀至顶峰。但梦想与现实之间&#xff0c;究竟有多远的距离&#xff1f;今天&#xff0c;让我们一起探索那些看似遥不可及&#xff0c;却又…

Unity UGUI 之 自动布局组件

本文仅作学习笔记与交流&#xff0c;不作任何商业用途 本文包括但不限于unity官方手册&#xff0c;唐老狮&#xff0c;麦扣教程知识&#xff0c;引用会标记&#xff0c;如有不足还请斧正 本文在发布时间选用unity 2022.3.8稳定版本&#xff0c;请注意分别 1.什么是自动布局组件…

微服务注册中心

目录 1.微服务的注册中心 1.1 注册中⼼的主要作⽤ 1.2 常⻅的注册中⼼ 2.nacos简介 2.1 nacos实战⼊⻔ 2.2.1 搭建nacos环境 2.2.2 将商品微服务注册到nacos 3.服务调⽤Ribbon⼊⻔ 3.1 Ribbon概述 3.1.1 什么是Ribbon 3.1.2 Ribbon的主要作⽤ 3.2.2 ⼯程改造 4.服务…

openmv学习笔记(24电赛备赛笔记)

#openmv简介 openmv一种小型&#xff0c;可编程机器视觉摄像头&#xff0c;设计应用嵌入式应用和计算边缘&#xff0c;是图传模块&#xff0c;或者认为是一种&#xff0c;具有图像处理功能的单片机&#xff0c;提供多种接口&#xff08;I2C SPI UART CAN ADC DAC &#xff0…

204、【动态规划】牛客网 ——DP3 跳台阶扩展问题(Python版本)

题目描述 原题链接&#xff1a;DP3 跳台阶扩展问题 解题思路 一个DP问题&#xff0c;相比于普通爬楼&#xff08;只能爬一层或者两层&#xff09;对应的状态函数为 d p [ i ] d p [ i − 1 ] d p [ i − 2 ] dp[i] dp[i - 1] dp[i - 2] dp[i]dp[i−1]dp[i−2]。本题的dp…

vue3+g2plot实现词云图

词云图 效果预览: 核心代码: import {WordCloud } from @antv/g2plot;fetch(https://gw.alipayobjects.com/os/antfincdn/jPKbal7r9r/mock.json).then((res) => res.json()).then((data) => {const wordCloud = new WordCloud(container, {data,wordField: x,weigh…

秒懂Linux之权限

目录 一.Linux用户 二.文件权限 2.1 权限属性 chmod命令 chown与chgrp命令 2.2 文件类型 file指令 常见类型 2.3 常见权限问题 问题一&#xff1a; 问题二&#xff1a; 问题三&#xff1a; 一.Linux用户 Linux 下有两种用户&#xff1a;超级用户&#xff08; root …

kettle从入门到精通 第八十课 ETL之kettle kettle中的json对象字段写入postgresql中的json字段

场景&#xff1a;源数据库表为mysql的其中有json字段&#xff0c;通过kettle 查询出来 插入到目标数据库 postgresql中&#xff0c;对应的表中也有json字段。。但是报错&#xff0c;提示kettle查询出来是varchar的的字段&#xff0c;无法插入到目标数据库中。 1、创建测试表。 …

VBA技术资料MF180:将某个文件夹中的某类图片导入Word

我给VBA的定义&#xff1a;VBA是个人小型自动化处理的有效工具。利用好了&#xff0c;可以大大提高自己的工作效率&#xff0c;而且可以提高数据的准确度。“VBA语言専攻”提供的教程一共九套&#xff0c;分为初级、中级、高级三大部分&#xff0c;教程是对VBA的系统讲解&#…

【C++进阶学习】第九弹——哈希的原理与实现——开放寻址法的讲解

前言&#xff1a; 在前面&#xff0c;我们已经学习了很多存储机构&#xff0c;包括线性存储、树性存储等&#xff0c;并学习了多种拓展结构&#xff0c;效率也越来越高&#xff0c;但是是否有一种存储结构可以在大部分问题中都一次找到目标值呢&#xff1f;哈希可能能实现 目录…

【C++】C++应用案例-翻转数组

翻转数组&#xff0c;就是要把数组中元素的顺序全部反过来。比如一个数组{1,2,3,4,5,6,7,8}&#xff0c;翻转之后就是{8,7,6,5,4,3,2,1}。 &#xff08;1&#xff09;另外创建数组&#xff0c;反向填入元素 数组是将元素按照顺序依次存放的&#xff0c;长度固定。所以如果想要…

C++ | Leetcode C++题解之第283题移动零

题目&#xff1a; 题解&#xff1a; class Solution { public:void moveZeroes(vector<int>& nums) {int n nums.size(), left 0, right 0;while (right < n) {if (nums[right]) {swap(nums[left], nums[right]);left;}right;}} };

Go语言编程 学习笔记整理 第2章 顺序编程 前半部分

前言&#xff1a;《Go语言编程》编著 许式伟 吕桂华 等 1.1 变量 var v1 int var v2 string var v3 [10]int // 数组 var v4 []int // 数组切片 var v5 struct { f int } var v6 *int // 指针 var v7 map[string]int // map&#xff0c;key为string类型&#xff0c;value为in…

shell脚本(fifteen day)

一、shell概述 1、shell概念 &#xff08;1&#xff09;shell 英文翻译过来是外壳的意思&#xff0c;作为计算机语言来理解可以认为它是操作系统的外壳。可以通过shell 命令来操作和控制操作系统&#xff0c;比如Linux中的shell命令就包括 ls、cd、pwd 等等。 &#xff08;2&a…