jjwt -- Token 生成解析技术指南


引言

JWT(JSON Web Token)是一种基于JSON的、用于双方之间安全传输信息的简洁的、URL安全的令牌标准。在现代Web应用程序中,JWT作为一种高效且安全的认证机制,被广泛应用于用户身份验证和信息交换场景。本文旨在详细介绍JWT Token的生成与解析过程,为开发者提供一份专业的技术参考。

JJWT简介

JJWT是一个开源的Java库,专门用于处理JSON Web Tokens(JWT)。JWT是一种基于JSON的、用于双方之间安全传输信息的简洁的、URL安全的令牌标准(RFC 7519)。通过JJWT,开发者可以轻松地在Java应用程序中生成、解析和验证JWT。

JWT结构概述

JWT由三个部分组成,它们通过“.”分隔符连接而成:Header(头部)、Payload(负载)和Signature(签名)。
  • Header‌:包含令牌的元数据,如签名算法和令牌类型,通常采用Base64Url编码。
  • Payload‌:包含实际需要传递的数据,如用户ID、过期时间等官方字段,同样采用Base64Url编码。
  • Signature‌:对Header和Payload进行签名,以确保数据的完整性和来源的真实性。签名通常使用指定的算法和密钥生成。

添加依赖

要在Java项目中使用JJWT,首先需要在项目的`pom.xml` 文件中添加相应的依赖。以下是一个Maven依赖的示例:
<dependency>
  <groupId>io.jsonwebtoken</groupId>
  <artifactId>jjwt-api</artifactId>
  <version>0.12.3</version>
</dependency>
<dependency>
  <groupId>io.jsonwebtoken</groupId>
  <artifactId>jjwt-impl</artifactId>
  <version>0.12.3</version>
</dependency>
<dependency>
  <groupId>io.jsonwebtoken</groupId>
  <artifactId>jjwt-jackson</artifactId>
  <version>0.12.3</version>
</dependency>

生成Token

使用JJWT生成Token,首先,需要创建一个` Claims` 对象来设置Token的负载信息。然后,使用` Jwts.builder()` 方法构建Token,并指定签名算法和签名密钥。以下是一个生成Token的示例代码:
/**
     * 生成JWT(JSON Web Token)
     *
     * @param key 用于签名的密钥
     * @return 生成的JWT字符串
     */
    public static String generateToken(Key key) {
        // 设置JWT的过期时间
        long nowMillis = System.currentTimeMillis();
        Date now = new Date(nowMillis);
        long expMillis = nowMillis + EXPIRATION_TIME; // 1小时后过期
        Date exp = new Date(expMillis);

        // 创建 claims
        Map<String, Object> claims = new HashMap<>();
        claims.put("sub", "subject"); // 设置JWT的主题
        claims.put("name", "Shore");

        // 生成JWT
        return Jwts.builder()
                .id(getUUID())
                .subject("subject")
                .claims(claims) // 设置JWT的主题
                .issuer("issuer")
                .issuedAt(now)    // 设置JWT的签发时间
                .expiration(exp)  // 设置JWT的过期时间
                .signWith(key) // 使用算法签名JWT
                .audience() // 设置JWT的接收者
                .add("audience")
                .and()
                .header()
                .add("alg", "HS256")
                .and()
                .compact(); // 生成紧凑的JWT字符串
    }

在上述代码中,我们创建了一个包含用户ID(<font style="color:rgb(51, 51, 51);">sub</font>字段)的负载,并设置了Token的过期时间。然后,使用HS256算法和指定的密钥对Token进行签名,并生成最终的Token字符串。

校验Token

要校验Token,需要使用`Jwts.parser()` 方法来构建一个解析器,并设置签名密钥,根据解析过程是否抛出异常来判断 token 是否有效。以下是一个校验Token的示例:
/**
     * 验证JWT(JSON Web Token)的有效性
     * 此方法使用提供的密钥对JWT进行验证,以确保其未被篡改且有效
     * 它支持使用SecretKey(对称密钥)或PublicKey(非对称密钥)进行验证
     *
     * @param token 待验证的JWT字符串
     * @param key 用于验证JWT的密钥,可以是SecretKey或PublicKey实例
     * @return 如果JWT有效则返回true,否则返回false
     */
    public static boolean validateToken(String token, Key key) {
        try {
            // 检查token和密钥是否为空或无效
            if (StringUtils.isBlank(token) || Objects.isNull(key)) {
                return false;
            }
            // 根据密钥类型验证JWT
            if (key instanceof SecretKey) {
                // 使用SecretKey验证JWT
                Jwts.parser().verifyWith((SecretKey) key).build().parseSignedClaims(token);
            } else if (key instanceof PublicKey) {
                // 使用PublicKey验证JWT
                Jwts.parser().verifyWith((PublicKey) key).build().parseSignedClaims(token);
            }
            // 验证成功,返回true
            return true;
        } catch (Exception e) {
            // 验证失败,输出错误信息并返回false
            System.err.println("Failed to validate token: " + e.getMessage());
            return false;
        }
    }

上述代码可以接收不同方式加密的token,对称或者非对称加密,根据不同的类型尝试解析来验证token。

解析Token

要解析Token,你需要使用`Jwts.parser()` 方法来构建一个解析器,并设置签名密钥。以下是一个解析Token的示例:
/**
     * 解析JWT令牌,返回令牌中的声明信息
     *
     * @param token 待解析的JWT令牌字符串
     * @param key 用于验证令牌签名的密钥,可以是SecretKey或PublicKey实例
     * @return 返回Claims对象,包含令牌中的所有声明如果解析失败或密钥类型不匹配,则返回null
     */
    public static Claims parseToken(String token, Key key) {
        try {
            // 检查token和密钥是否为空或无效
            if (StringUtils.isBlank(token) || Objects.isNull(key)) {
                return null;
            }
            // 根据密钥类型解析令牌
            if (key instanceof SecretKey) {
                // 使用SecretKey解析令牌
                return Jwts.parser().verifyWith((SecretKey) key).build().parseSignedClaims(token).getPayload();
            } else if (key instanceof PublicKey) {
                // 使用PublicKey解析令牌
                return Jwts.parser().verifyWith((PublicKey) key).build().parseSignedClaims(token).getPayload();
            } else {
                // 不支持的密钥类型
                return null;
            }
        } catch (Exception e) {
            // 其他异常,比如token格式不正确、解析失败等
            System.err.println("Failed to parse token: " + e.getMessage());
            return null; // token无效
        }
    }

在上述代码中,我们解析不同方式加密的Token,如果解析失败则返回null,成功则返回Claims对象。

加密方式

对称加密

使用 KeyPairGenerator 提供的方法生成对称密钥。以下是生成对称密钥的代码示例:
/**
     * 生成对称密钥(AES)
     *
     * @param keyLength 密钥长度(如:128, 192, 256)
     * @return 生成的对称密钥的Base64编码字符串
     * @throws NoSuchAlgorithmException 如果指定的加密算法不可用
     */
    public static String generateSymmetricKey(int keyLength) throws NoSuchAlgorithmException {
        KeyGenerator keyGenerator = KeyGenerator.getInstance("AES");
        keyGenerator.init(keyLength);
        return Base64.getEncoder().encodeToString(keyGenerator.generateKey().getEncoded()) ;
    }

有了对称密钥以后,我们可以使用生成的密钥生成解析token,以下是代码示例:

public static void main(String[] args) {
        // 生成密钥,三种对称加密算法(哈希函数不同,安全性不同)
//        System.out.println(Base64.getEncoder().encodeToString(Keys.secretKeyFor(SignatureAlgorithm.HS256).getEncoded()));
//        System.out.println(Base64.getEncoder().encodeToString(Keys.secretKeyFor(SignatureAlgorithm.HS384).getEncoded()));
//        System.out.println(Base64.getEncoder().encodeToString(Keys.secretKeyFor(SignatureAlgorithm.HS512).getEncoded()));

        try {
            // 生成对称密钥
            SecretKey key = Keys.hmacShaKeyFor(KeyGeneratorUtils.generateSymmetricKey(256).getBytes(StandardCharsets.UTF_8));
            String jwt = generateToken(key);
            System.out.println(jwt);
            boolean valid = validateToken(jwt, key);
            System.out.println(valid);
            if (valid) {
                Claims claims = parseToken(jwt, key);
                System.out.println(claims);
                if (Objects.nonNull(claims)) {
                    System.out.println(claims.getSubject());
                }
            }
        } catch (Exception e) {
            System.err.println("Failed to generate asymmetric key: " + e.getMessage());
        }

    }

除了使用 KeyPairGenerator 方式生成密钥外,还可以使用上述代码中注释方法快捷生成密钥。以下是执行结果截图:

非对称加密

同样使用 KeyPairGenerator 提供的方法生成非对称密钥。以下是生成非对称密钥的代码示例:
/**
     * 生成非对称密钥对(RSA)
     *
     * @param keySize 密钥大小(如:1024, 2048)
     * @return 生成的非对称密钥对的Base64编码字符串数组,第一个元素是公钥,第二个元素是私钥
     * @throws NoSuchAlgorithmException 如果指定的加密算法不可用
     */
    public static KeyPair generateAsymmetricKeyPair(int keySize) throws NoSuchAlgorithmException {
        KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
        keyPairGenerator.initialize(keySize);

        return keyPairGenerator.generateKeyPair();
    }

通过上述代码生成非对称密钥以后,我们可以使用生成的密钥生成解析token,以下是代码示例:

public static void main(String[] args) {
        try {
            // 生成非对称密钥
            KeyPair keyPair = KeyGeneratorUtils.generateAsymmetricKeyPair(2048);

            String jwt2 = generateToken(keyPair.getPrivate());
            System.out.println(jwt2);
            boolean valid2 = validateToken(jwt2, keyPair.getPublic());
            System.out.println(valid2);
            if (valid2) {
                Claims claims = parseToken(jwt2, keyPair.getPublic());
                System.out.println(claims);
                if (Objects.nonNull(claims)) {
                    System.out.println(claims.getSubject());
                }
            }
        } catch (Exception e) {
            System.err.println("Failed to generate asymmetric key: " + e.getMessage());
        }

    }

生成密钥后我们使用私钥生成token,然后使用公钥校验解析token,以下是执行结果截图:

总结

本文详细介绍了JWT Token的生成与解析过程,包括JWT的结构概述、Token生成示例和Token解析示例。通过本文的介绍,开发者可以更加深入地了解JWT的工作原理,并在实际项目中灵活应用JWT技术,提高应用程序的安全性和可扩展性。希望本文能为开发者提供一份有价值的技术参考。

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

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

相关文章

第 2 天:创建你的第一个 UE5 C++ 项目!

&#x1f3af; 目标&#xff1a; 掌握 UE5 C 项目的创建流程&#xff0c;了解代码结构&#xff0c;并成功运行第一个 C 类&#xff01; 1️⃣ 创建 UE5 C 项目 在 UE5 中&#xff0c;C 项目可以与蓝图&#xff08;Blueprint&#xff09;结合使用&#xff0c;让游戏逻辑更灵活…

RabbitMQ 从入门到精通:从工作模式到集群部署实战(二)

接上篇&#xff1a;《RabbitMQ 从入门到精通&#xff1a;从工作模式到集群部署实战&#xff08;一&#xff09;》 链接 文章目录 4.安装RabbitMQ Messaging Topology Operator 裸金属环境部署RabbitMQ部署单实例部署集群 4.安装RabbitMQ Messaging Topology Operator 使用 cer…

vs code 使用教程

一、定义 多行注释vs 找不到上层文件路径选择 或 创建python 虚拟环境git 远程克隆及推送vs code 文件路径vs 使用tensorboard 二、使用 学习网站&#xff1a;https://learn.microsoft.com/zh-cn/visualstudio/python/?viewvs-2022性能分析&#xff1a;https://learn.micros…

【Elasticsearch】terms聚合误差问题

Elasticsearch中的聚合查询在某些情况下确实可能存在误差&#xff0c;尤其是在处理分布式数据和大量唯一值时。这种误差主要来源于以下几个方面&#xff1a; 1.分片数据的局部性 Elasticsearch的索引通常被分成多个分片&#xff0c;每个分片独立地计算聚合结果。由于数据在分…

BUU22 [护网杯 2018]easy_tornado 1

打开题目以后出现三个文件&#xff0c;查看源代码&#xff0c;突破口在于这三个文件都有特殊的格式 python的tornado漏洞 Tornado 是一个用 Python 编写的 Web 框架&#xff08;和flask一样&#xff0c;只不过flask是轻量级的&#xff0c;而tornado可以处理高流量&#xff09…

QT修仙之路1-1--遇见QT

文章目录 遇见QT二、QT概述2.1 定义与功能2.2 跨平台特性2.3 优点汇总 三、软件安装四、QT工具介绍(重要)4.1 Assistant4.2 Designer4.3 uic.exe4.4 moc.exe4.5 rcc.exe4.6 qmake4.7 QTcreater 五、QT工程项目解析(作业)5.1 配置文件&#xff08;.pro&#xff09;5.2 头文件&am…

寒假2.5

题解 web:[网鼎杯 2020 朱雀组]phpweb 打开网址&#xff0c;一直在刷新&#xff0c;并有一段警告 翻译一下 查看源码 每隔五秒钟将会提交一次form1&#xff0c;index.php用post方式提交了两个参数func和p&#xff0c;func的值为date&#xff0c;p的值为Y-m-d h:i:s a 执行fu…

计算机中数值表示:原码、反码、补码与移码

1 前言 计算机科学中&#xff0c;数字的表示方式至关重要&#xff0c;因为计算机内部只能识别处理二进制数据。为了在计算机中实现对整数的表示&#xff0c;提出了多种数值编码方式&#xff0c;其中最常用的是原码、反码、补码和移码。 2 原码 2.1 原码的定义 原码(Signed …

硬件实现I2C常用寄存器简单介绍

引言 在深入探讨I2C外设的具体案例之前&#xff0c;理解其核心寄存器的配置至关重要。这些寄存器不仅控制着I2C模块的基本操作模式&#xff0c;如数据传输速率和地址识别&#xff0c;还负责管理更复杂的通信需求&#xff0c;例如中断处理、DMA交互及错误检测与恢复。接下来的内…

分析用户请求K8S里ingress-nginx提供的ingress流量路径

前言 本文是个人的小小见解&#xff0c;欢迎大佬指出我文章的问题&#xff0c;一起讨论进步~ 我个人的疑问点 进入的流量是如何自动判断进入iptables的四表&#xff1f;k8s nodeport模式的原理&#xff1f; 一 本机环境介绍 节点名节点IPK8S版本CNI插件Master192.168.44.1…

linux中,软硬链接的作用和使用

一、软硬链接的作用 软硬链接&#xff0c;是大家所熟系的内容了。链接就是方便人使用电脑上访问文件、方便进程访问文件的工具。比如软连接大家都有见过&#xff0c;在安装某款软件的时候要不要添加快捷方式。在windows系统上&#xff0c;我们右键点击文件的时候按‘s’就能创建…

kalman滤波器C++设计仿真实例第三篇

1. 仿真场景 水面上有条船在做匀速直线航行&#xff0c;航行过程中由于风和浪的影响&#xff0c;会有些随机的干扰&#xff0c;也就是会有些随机的加速度作用在船身上&#xff0c;这个随机加速度的均方差大约是0.1&#xff0c;也就是说方差是0.01。船上搭载GPS设备&#xff0c;…

ubuntu20.04+RTX4060Ti大模型环境安装

装显卡驱动 这里是重点&#xff0c;因为我是跑深度学习的&#xff0c;要用CUDA&#xff0c;所以必须得装官方的驱动&#xff0c;Ubuntu的附件驱动可能不太行. 进入官网https://www.nvidia.cn/geforce/drivers/&#xff0c;选择类型&#xff0c;最新版本下载。 挨个运行&#…

[c语言日寄]浮点数在内存中的储存

【作者主页】siy2333 【专栏介绍】⌈c语言日寄⌋&#xff1a;这是一个专注于C语言刷题的专栏&#xff0c;精选题目&#xff0c;搭配详细题解、拓展算法。从基础语法到复杂算法&#xff0c;题目涉及的知识点全面覆盖&#xff0c;助力你系统提升。无论你是初学者&#xff0c;还是…

Yageo国巨的RC系列0402封装1%电阻库来了

工作使用Cadence多年&#xff0c;很多时候麻烦的就是整理BOM&#xff0c;因为设计原理图的时候图省事&#xff0c;可能只修改value值和封装。 但是厂家&#xff0c;规格型号&#xff0c;物料描述等属性需要在最后的时候一行一行的修改&#xff0c;繁琐又容易出错&#xff0c;过…

【文档智能】Qwen2.5-VL在版式分析和表格识别上的实际评测效果

qwen开年开源了Qwen2.5-VL系列权重模型&#xff0c;笔者观察到相较于传统的多模态系列&#xff0c;增加了文档理解功能。笔者以文档智能中两个比较重要的任务版式分析和表格识别&#xff0c;笔者直接测试下Qwen2.5-VL-72B的效果。 版式分析 case1 case2 这个case没有输出bbox…

【计算机组成原理】1_绪论

chap1 绪论 1. 国产芯片现状 MIPS阵营&#xff1a;龙芯X86阵营&#xff08;常见于桌面和服务器&#xff09;&#xff1a;兆芯&#xff08;VIA&#xff09;&#xff0c;海光&#xff08;AMD&#xff09;ARM阵营&#xff08;常见于移动嵌入式、手机平板等&#xff09;&#xff…

解锁反序列化漏洞:从原理到防护的安全指南

目录 前言 一、什么是反序列化 二、反序列化漏洞原理 三、反序列化漏洞的危害 &#xff08;一&#xff09;任意代码执行 &#xff08;二&#xff09;权限提升 &#xff08;三&#xff09;数据泄露与篡改 四、常见的反序列化漏洞场景 &#xff08;一&#xff09;PHP 反…

openGauss 3.0 数据库在线实训课程1:学习数据库状态查看

openGauss数据库状态查看 前提 我正在参加21天养成好习惯| 第二届openGauss每日一练活动 课程详见&#xff1a;openGauss 3.0.0数据库在线实训课程 学习目标 学习从操作系统层面和使用openGauss工具查看数据库的状态、版本和数据文件目录。 课程作业 gs_ctl是openGauss提…

[含文档+PPT+源码等]精品基于Python实现的django个性化健康餐计划订制系统

软件开发环境及开发工具&#xff1a; 开发语言&#xff1a;python 使用框架&#xff1a;Django 前端技术&#xff1a;JavaScript、VUE.js&#xff08;2.X&#xff09;、css3 开发工具&#xff1a;pycharm、Visual Studio Code、HbuildX 数据库&#xff1a;MySQL 5.7.26&am…