使用 Spring Boot 实现 JWT 生成与验证的自定义类

news/2024/12/22 17:27:07/

在现代 web 应用中,JWT(JSON Web Tokens)被广泛用于用户身份验证。本文将展示如何创建一个自定义的 JWT 生成与验证类 JwtPlus,该类使用对称加密算法,并支持灵活的配置选项。我们将通过以下步骤实现这个功能:

1. 背景介绍

JWT 的结构通常包含三个部分:头部(Header)、载体(Payload)和签名(Signature)。通过对这三个部分进行编码和加密,JWT 能够安全地传递用户信息。有效的 JWT 需要在客户端和服务器之间传递,因此确保它们的安全性是至关重要的。

2. 主要功能需求

  • 生成 JWT:支持自定义 Header 和 Claims,并使用对称加密算法生成签名。
  • 验证 JWT:能够验证签名的有效性,并提取载体部分的数据。
  • 支持自定义算法:允许开发者使用不同的加密算法。

3. 实现步骤

3.1. 创建 Algorithm

该类用于定义加密算法及其密钥:

public class Algorithm {private String name;private String key;public Algorithm(String name, String key) {this.name = name;this.key = key;}public String getName() {return name;}public String getKey() {return key;}
}

3.2. 创建 JwtPlus

这是我们主要的 JWT 处理类,包含生成和验证的逻辑。

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;public class JwtPlus {private Map<String, String> header;private Map<String, String> claims;private Algorithm algorithm;// 私有构造函数,防止直接实例化private JwtPlus(Builder builder) {this.header = builder.header;this.claims = builder.claims;this.algorithm = builder.algorithm;}// 静态方法,用于获取 Builder 实例public static Builder builder() {return new Builder();}// 静态方法,用于获取 JwtVerifier 实例public static JwtVerifier require() {return new JwtVerifier();}// 生成 Token 方法public String sign() {if (header == null || header.isEmpty()) {header = new HashMap<>();header.put("alg", algorithm.getName());header.put("typ", "JWT");}String headerEncoded = encodeBase64(mapToString(header));String claimsEncoded = encodeBase64(mapToString(claims));String signature = generateSignature(headerEncoded, claimsEncoded);return headerEncoded + "." + claimsEncoded + "." + signature;}// 生成签名private String generateSignature(String header, String claims) {try {String data = header + "." + claims;Mac mac = Mac.getInstance(algorithm.getName());SecretKeySpec secretKeySpec = new SecretKeySpec(algorithm.getKey().getBytes(StandardCharsets.UTF_8), algorithm.getName());mac.init(secretKeySpec);byte[] signatureBytes = mac.doFinal(data.getBytes(StandardCharsets.UTF_8));return encodeBase64(new String(signatureBytes, StandardCharsets.UTF_8));} catch (Exception e) {throw new RuntimeException("Error generating signature", e);}}// 内部类 JwtVerifierpublic static class JwtVerifier {private String secretKey;private Algorithm algorithm;public JwtVerifier secret(String secretKey) {this.secretKey = secretKey;return this;}public JwtVerifier algorithm(Algorithm algorithm) {this.algorithm = algorithm;return this;}public boolean verify(String token) {String[] parts = token.split("\\.");if (parts.length != 3) {return false;}String headerEncoded = parts[0];String claimsEncoded = parts[1];String signature = parts[2];String expectedSignature = JwtPlus.builder().claims(new HashMap<>()) // 空 claims 仅用于签名.algorithm(algorithm).build().generateSignature(headerEncoded, claimsEncoded);return expectedSignature.equals(signature);}public Map<String, String> getClaims(String token) {String[] parts = token.split("\\.");if (parts.length != 3) {throw new IllegalArgumentException("Invalid Token format");}String claimsEncoded = parts[1];return stringToMap(decodeBase64(claimsEncoded));}}// 其他方法保持不变private static String encodeBase64(String data) {return Base64.getUrlEncoder().withoutPadding().encodeToString(data.getBytes(StandardCharsets.UTF_8));}private static String decodeBase64(String data) {return new String(Base64.getUrlDecoder().decode(data), StandardCharsets.UTF_8);}private static String mapToString(Map<String, String> map) {StringBuilder sb = new StringBuilder();for (Map.Entry<String, String> entry : map.entrySet()) {sb.append(entry.getKey()).append("=").append(entry.getValue()).append(";");}return sb.toString();}private static Map<String, String> stringToMap(String token) {Map<String, String> map = new HashMap<>();String[] pairs = token.split(";");for (String pair : pairs) {String[] keyValue = pair.split("=");if (keyValue.length == 2) {map.put(keyValue[0], keyValue[1]);}}return map;}// Builder 类public static class Builder {private Map<String, String> header = new HashMap<>();private Map<String, String> claims = new HashMap<>();private Algorithm algorithm = new Algorithm("HmacSHA256", "default_secret_key");public Builder withHeader(Map<String, String> header) {this.header.putAll(header);return this;}public Builder claim(String key, String value) {this.claims.put(key, value);return this;}public Builder claims(Map<String, String> claims) {this.claims.putAll(claims);return this;}public Builder algorithm(Algorithm algorithm) {this.algorithm = algorithm;return this;}public JwtPlus build() {return new JwtPlus(this);}}
}

4. 调用示例

以下是如何使用 JwtPlusJwtVerifier 的示例:

public class TokenExample {public static void main(String[] args) {// 使用 builder 模式生成 TokenAlgorithm algorithm = new Algorithm("HmacSHA256", "your_secret_key");String token = JwtPlus.builder().claim("userId", "12345").claim("role", "admin").algorithm(algorithm).build().sign();System.out.println("Generated Token: " + token);// 使用 JwtVerifier 验证 TokenJwtPlus.JwtVerifier verifier = JwtPlus.require().secret("your_secret_key").algorithm(algorithm);boolean isValid = verifier.verify(token);System.out.println("Is Token valid? " + isValid);// 获取 Token 中的载体部分Map<String, String> claims = verifier.getClaims(token);System.out.println("Claims: " + claims);}
}

5. 实现原理与方法

  1. Token 结构:JWT 由三部分组成,分别为 Header、Payload 和 Signature。Header 指定了所使用的签名算法,Payload 存放用户信息,Signature 则是使用 Header 和 Payload 生成的。
  2. 生成 JWT:
  • 使用 Builder 模式构建 JWT 对象。
  • 编码 Header 和 Payload,并生成签名。
  • 最终将三个部分通过点(.)连接成一个字符串。
  1. 验证 JWT:
  • 使用 JwtVerifier 类来验证 JWT 的有效性。
  • 验证过程包括拆分 Token,重新生成签名,并与原始签名进行比较。
  1. 灵活性:通过 Algorithm 类,可以方便地实现对称加密算法的切换,使得代码更加灵活且易于扩展。

结论

本文展示了如何使用 Java 创建一个自定义的 JWT 生成与验证类,具有灵活的算法选择和安全的签名生成。这种方法为开发现代 web 应用提供了可靠的身份验证机制,同时保持了代码的可维护性和扩展性。希望这能帮助你在项目中实现 JWT 认证!


http://www.ppmy.cn/news/1535691.html

相关文章

【JavaEE】【多线程】进程与线程的概念

目录 进程系统管理进程系统操作进程进程控制块PCB关键属性cpu对进程的操作进程调度 线程线程与进程线程资源分配线程调度 线程与进程区别线程简单操作代码创建线程查看线程 进程 进程是操作系统对一个正在运行的程序的一种抽象&#xff0c;可以把进程看做程序的一次运行过程&a…

【PostgreSQL】提高篇——深入了解不同类型的 JOIN(INNER JOIN、LEFT JOIN、RIGHT JOIN、FULL JOIN)应用操作

1. JOIN 的基础概念 在 SQL 中&#xff0c;JOIN 是用于从两个或多个表中组合行的操作。JOIN 允许我们根据某些条件将表中的数据关联在一起。常见的 JOIN 类型包括&#xff1a; INNER JOIN&#xff1a;仅返回两个表中满足连接条件的行。LEFT JOIN&#xff08;或 LEFT OUTER JO…

美国静态住宅IP代理怎么定期更换?

在互联网使用中&#xff0c;P代理被广泛应用于许多方面&#xff0c;如网络安全测试、数据采集、访问受限制内容等。然而&#xff0c;为了维护隐私安全和避免被封禁&#xff0c;定期更换IP地址是必要的。特别是对于每个用户&#xff0c;定期更换IP地址更是至关重要。本文将探讨美…

网络通信——OSPF协议(基础篇)

这里基础是因为没有讲解OSPF中的具体算法过程&#xff0c;以及其中很多小细节。后续会更新。 目录 一.OSPF的基础信息 二.认识OSPF中的Router ID 三.OSPF中的三张表 四.OSPF中的度量方法&#xff08;计算开销值&#xff09; 五. OSPF选举DR和BDR&#xff08;就是这个区域…

wpf加载带材料的3D模型(下载的3D预览一样有纹理)

背景&#xff1a;最近真的是忙啊&#xff0c;累出汁水了 整体效果&#xff1a; 放大可以看清砖头&#xff1a; 1、需要自己准备好3D模型&#xff0c;比如我这里是下载的这里的3D Warehouse&#xff0c;下载Collada File格式文件 2、解压可以看到一个model.dae和材料的文件夹&…

Redisson的trylock()与lock()区别

1、使用方法 RLock lock redissonClient.getLock("test");lock.lock();try {// 业务逻辑} finally {lock.unlock();}RLock lock redissonClient.getLock("test");boolean result lock.tryLock();if (result) {try {// 业务逻辑} finally {lock.unlock()…

北交大研究突破:塑料光纤赋能低成本无摄像头AR/VR眼动追踪技术

北交大研究&#xff1a;探索无摄像头低成本AR/VR眼动追踪新路径 在AR/VR技术领域&#xff0c;眼动追踪作为一项关键技术&#xff0c;对于提升用户体验、优化渲染效率具有重要意义。然而&#xff0c;传统的眼动追踪方案多依赖于高成本的摄像头&#xff0c;这不仅增加了设备的制造…

一、Python(介绍、环境搭建)

一、介绍 Python 是一种高级编程语言&#xff0c;具有简洁易读的语法、丰富的库和强大的功能。Python是解释型语言&#xff0c;运行代码必须依赖安装好的解释器。Python目前存在两个版本&#xff1a;Python2、Python3&#xff08;主流使用&#xff09; 二、环境搭建 1.安装P…