公私钥非对称加密 生成和验证JSON Web Token (JWT)

2023-09-18 14:38:48

前言

这是我在这个网站整理的笔记,关注我,接下来还会持续更新。 作者:神的孩子都在歌唱

公私钥非对称加密 生成和验证JSON Web Token

什么是JSON Web Token (JWT)

JSON Web Token (JWT) 是一种轻量级的身份验证和授权机制,由三部分组成:头部(Header)、载荷(Payload)和签名(Signature)。其中头部和载荷都是Base64编码的JSON对象,签名是对头部、载荷和秘钥进行加密生成的。

JWT的优点在于它是一种无状态的身份验证机制,因此可以在分布式系统中广泛使用。JWT通常作为API的身份验证机制,客户端在请求中携带JWT token,服务端通过验证JWT token来确定请求的合法性。

使用JWT作为API的身份验证机制可以避免服务器保存用户登录状态,从而提高系统的可扩展性和安全性。在实际开发中,可以根据具体需求来选择不同的加密算法和秘钥长度。

Java程序中生成和验证JWT

以下是一个Java程序,用于生成和验证JSON Web Token (JWT)。该程序使用了RSA非对称加密算法生成公私钥对,并使用私钥构建JWT token,设置了主题、签发时间、过期时间和一个自定义声明。最后,使用公钥验证JWT token,并从中获取主题信息和自定义声明。

package com.ugdsec.common.auth.common.utils;

import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jws;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;

import java.security.*;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;
import java.util.Date;

public class JwtExample {

    public static void main(String[] args) throws NoSuchAlgorithmException, InvalidKeySpecException {

        // 生成RSA公私钥对
        KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
        keyPairGenerator.initialize(2048);
        KeyPair keyPair = keyPairGenerator.generateKeyPair();
        PrivateKey privateKey = keyPair.getPrivate();
        PublicKey publicKey = keyPair.getPublic();
        String publicKeyString = Base64.getEncoder().encodeToString(publicKey.getEncoded());
        String privateKeyString = Base64.getEncoder().encodeToString(privateKey.getEncoded());

        // 将公钥字符串转换为公钥对象
        byte[] publicKeyBytes = Base64.getDecoder().decode(publicKeyString);
        X509EncodedKeySpec publicKeySpec = new X509EncodedKeySpec(publicKeyBytes);
        publicKey = KeyFactory.getInstance("RSA").generatePublic(publicKeySpec);

        // 将私钥字符串转换为私钥对象
        byte[] privateKeyBytes = Base64.getDecoder().decode(privateKeyString);
        PKCS8EncodedKeySpec privateKeySpec = new PKCS8EncodedKeySpec(privateKeyBytes);
        privateKey = KeyFactory.getInstance("RSA").generatePrivate(privateKeySpec);

        // 构建JWT token
        String jwtToken = Jwts.builder()
            .setSubject("user")
            .setIssuedAt(new Date())
            .setExpiration(new Date(System.currentTimeMillis() + 3600000))
            .signWith(SignatureAlgorithm.RS256, privateKey)
            .claim("test","sdfs")
            .compact();
        System.out.println(jwtToken);

        // 验证JWT token
        Jws<Claims> jws = Jwts.parser()
            .setSigningKey(publicKey)
            .parseClaimsJws(jwtToken);

        // 获取JWT token中的主题信息和自定义声明
        String subject = jws.getBody().getSubject();
        String test = (String) jws.getBody().get("test");
        System.out.println("Subject: " + subject);
        System.out.println("Test: " + test);
    }
}

输出结果:

image-20230918141434440

代码解析

程序中使用了io.jsonwebtoken包提供的类和方法来生成和验证JWT token。具体分析如下:

  1. 导入所需的包
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jws;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;

import java.security.*;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;
import java.util.Date;
  1. 生成RSA公私钥对
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
keyPairGenerator.initialize(2048);
KeyPair keyPair = keyPairGenerator.generateKeyPair();
PrivateKey privateKey = keyPair.getPrivate();
PublicKey publicKey = keyPair.getPublic();
String publicKeyString = Base64.getEncoder().encodeToString(publicKey.getEncoded());
String privateKeyString = Base64.getEncoder().encodeToString(privateKey.getEncoded());

使用KeyPairGenerator类生成2048位的RSA公私钥对,将公私钥分别存储在publicKeyprivateKey变量中,并将它们对应的字符串分别存储在publicKeyStringprivateKeyString变量中。

  1. 将公私钥字符串转换为公私钥对象
byte[] publicKeyBytes = Base64.getDecoder().decode(publicKeyString);
X509EncodedKeySpec publicKeySpec = new X509EncodedKeySpec(publicKeyBytes);
publicKey = KeyFactory.getInstance("RSA").generatePublic(publicKeySpec);

byte[] privateKeyBytes = Base64.getDecoder().decode(privateKeyString);
PKCS8EncodedKeySpec privateKeySpec = new PKCS8EncodedKeySpec(privateKeyBytes);
privateKey = KeyFactory.getInstance("RSA").generatePrivate(privateKeySpec);

将公私钥对应的字符串转换成公私钥对象,以便后续使用。

  1. 构建JWT token
String jwtToken = Jwts.builder()
    .setSubject("user")
    .setIssuedAt(new Date())
    .setExpiration(new Date(System.currentTimeMillis() + 3600000))
    .signWith(SignatureAlgorithm.RS256, privateKey)
    .claim("test","sdfs")
    .compact();
System.out.println(jwtToken);

使用Jwts.builder()方法构建JWT token,设置了主题、签发时间、过期时间和一个自定义声明,并使用私钥进行签名。

  1. 验证JWT token
Jws<Claims> jws = Jwts.parser()
    .setSigningKey(publicKey)
    .parseClaimsJws(jwtToken);

使用公钥验证JWT token,并将解析后的结果存储在jws变量中。

  1. 获取JWT token中的主题信息和自定义声明
String subject = jws.getBody().getSubject();
String test = (String) jws.getBody().get("test");
System.out.println("Subject: " + subject);
System.out.println("Test: " + test);

作者:神的孩子都在歌唱
本人博客:https://blog.csdn.net/weixin_46654114
转载说明:务必注明来源,附带本人博客连接。

更多推荐

二叉树(相关术语、创建、遍历、最大深度问题)梳理总结

🍓简介:java系列技术分享(👉持续更新中…🔥)🍓初衷:一起学习、一起进步、坚持不懈🍓如果文章内容有误与您的想法不一致,欢迎大家在评论区指正🙏🍓希望这篇文章对你有所帮助,欢迎点赞👍收藏⭐留言📝🍓更多文章请点击文章目录一、二叉树1.1树的基本定义1.2树的相关术语1.3二叉树的基本定义1.4二叉查找树

OZON测评自养号技巧,提升店铺权重和销量,避免恶意跟卖

在中国的跨境商家眼中,OZON可能是一个陌生的名字,但在俄罗斯人眼中,它是一个家喻户晓的电商平台。自2016年开始在俄罗斯运营以来,OZON已经成为俄罗斯市场上备受欢迎的电商平台,为俄罗斯人提供了丰富多样的产品选择和便利的购物体验。迄今为止,OZON在俄罗斯市场的占有率已经超过了最早深耕俄系市场的速卖通。有市场的地方就

浅谈SpringMVC的请求流程

目录标题浅谈SpringMVC的请求流程SpringMVC的介绍SpringMVC的逻辑概念运行图解知识总结浅谈SpringMVC的请求流程对于SpringMVC而言重点是了解它的底层运行逻辑,从而可以根据其逻辑来进行实际业务的操作或者是利用原理增强业务的功能性,最终达到项目预期效果。SpringMVC的介绍Sprin

【数据库索引优化】

文章目录数据库索引优化1.选择合适的字段创建索引2.限值每张表上的索引数量3.被频繁更新的字段应该慎重建立索引4.尽可能考虑简历联合索引而不是单列索引5.避免冗余索引6.字符串类型的字段使用前缀索引代替普通索引7.避免索引失效8.删除长期未使用的索引数据库索引优化1.选择合适的字段创建索引不为NULL的字段:索引字段的

Postman应用——Variable变量使用(Global、Environment和Collection)

文章目录变量的使用同名变量优先级Postman内置变量Global、Environment和Collection变量设置,点击查看。变量的使用语法:{{变量名}}使用{{}}包裹变量名,引用设置好的变量。注意:Environment变量引用前需要先选择已有的环境,默认不选择任何环境,否则Environment变量不生效

动态码收款与扫码支付:深入剖析

随着移动支付的普及,越来越多的支付方式在我们的生活中出现,其中,动态码收款和扫码支付是两种常见的支付方式。本文将深入剖析这两种方式的差异,并探讨它们各自的优点和缺点。动态码收款,顾名思义,是指收款方提供一个动态生成的二维码,支付方扫描这个二维码进行支付。这种方式的主要优点是安全性高,因为每次交易的二维码都是唯一的,不易

热文推荐