JWT签名 0.12.3版本

打算接入微信智能对话平台,用到JWT AES 签名 记录一下

  • 环境依赖
  • JWT签名
    • 签名基本语句示范
    • JWT验证签名
    • HMAC 签名(Hash-based Message Authentication Code,散列消息认证码)
    • RSA 签名
    • ECDSA 签名(椭圆曲线数字签名算法)
    • EdDSA签名(爱德华兹曲线数字签名算法)
    • AES签名(对称加密)
    • 如果需要加密签名的话,请参考官方文档
      • 链接: [JWT ](https://github.com/jwtk/jjwt#jwt-encrypted-directly-with-a-secretkey)

环境依赖

下面展示一些 内联代码片

最新版本 jjwt-api
		<!-- https://mvnrepository.com/artifact/io.jsonwebtoken/jjwt-api -->
        <dependency>
            <groupId>io.jsonwebtoken</groupId>
            <artifactId>jjwt-api</artifactId>
            <version>0.12.3</version>
        </dependency>
        
 		<!-- https://mvnrepository.com/artifact/io.jsonwebtoken/jjwt-impl -->
        <dependency>
            <groupId>io.jsonwebtoken</groupId>
            <artifactId>jjwt-impl</artifactId>
            <version>0.12.3</version>
            <scope>runtime</scope>
        </dependency>

        <!-- https://mvnrepository.com/artifact/io.jsonwebtoken/jjwt-jackson -->
        <dependency>
            <groupId>io.jsonwebtoken</groupId>
            <artifactId>jjwt-jackson</artifactId>
            <version>0.12.3</version>
            <scope>runtime</scope>
        </dependency>
        

JWT签名

HMAC (基于哈希的消息身份验证代码)对 JWT 进行数字签名。
JWT 规范定义了 3 种标准 HMAC 签名算法:

HS256:具有 SHA-256 的 HMAC。这需要 256 位(32 字节)SecretKey或更大。
HS384:具有 SHA-384 的 HMAC。这需要 384 位(48 字节)SecretKey或更大。
HS512:具有 SHA-512 的 HMAC。这需要 512 位(64 字节)SecretKey或更大。

ES256:使用 P-256 和 SHA-256 的 ECDSA。这需要正好 256 位(32 字节)长的 EC 密钥。
ES384:使用 P-384 和 SHA-384 的 ECDSA。这需要正好 384 位(48 字节)长的 EC 密钥。
ES512:使用 P-521 和 SHA-512 的 ECDSA。这需要 EC 密钥的长度恰好为 521 位(65 或 66 字节,具体取决于格式)。

Ed25519:EdDSA使用曲线Ed25519。Ed25519算法密钥必须为 255 位长,并生成 512 位(64 字节)长的签名。
Ed448:EdDSA使用曲线Ed448。Ed448算法密钥必须为 448 位长,并生成 912 位(114 字节)长的签名。

A128GCM:使用 128 位(16 字节)SecretKey或更大的 AES GCM。
A192GCM:使用 192 位(24 字节)SecretKey或更大的 AES GCM。
A256GCM:使用 256 位(32 字节)SecretKey或更大的 AES GCM。
A128CBC-HS256:AES_128_CBC_HMAC_SHA_256使用 256 位(32 字节)SecretKey。
A192CBC-HS384:AES_192_CBC_HMAC_SHA_384使用 384 位(48 字节)SecretKey。
A256CBC-HS512:AES_256_CBC_HMAC_SHA_512使用 512 位(64 字节)SecretKey。


签名基本语句示范

 		//如果您不想考虑位长度要求,或者只是想让您的生活更轻松,
 		//JWT 提供了方便的构建器类,可以为任何给定的密钥生成足够安全的密钥 
        SecretKey secretKey = Jwts.SIG.HS256.key().build();
        //自定义秘钥也可以 , 不同的算法需要的秘钥长度不同
        //SecretKey key = Keys.hmacShaKeyFor("AWEQWEWE23123156qqqq465wqeqweqweqwewqeqweqweqweq4".getBytes(StandardCharsets.UTF_8)); // 你的密钥
        
        // 独立的Header头
        Header Headers = Jwts.header()
                .keyId("aKeyId")//秘钥ID, 一般不写
                .add("Key","Value")
                // ... 可add多个参数 ...
                .build();//构建对象

        //创建一个Claims对象,可以很多个参数
        Claims claims = Jwts.claims().subject("F").add("username", "Feng")
                .add("userid", "eqexta939c").build();

        Date now = new Date();
        Date expiration = new Date(now.getTime() + 700000);

        //直接使用Jwts的builder()方法构建完整对象
        String jwt = Jwts.builder()
                .header()  //构建header
                .add(Headers)// <----追加上面的独立头信息
                .add("key", "v")//自定义更多的头信息
                .and()//增加主体信息
                .subject("whatever")
                //负载(payload)
                .claim("img","123.png")//自定义信息
                .claim("url","https://xxx.com")//自定义信息
                .claims(claims)//上面创建的集合 或者可以自定义一个 java.util.Map map 对象也可以
                .issuedAt(now) // 当前时间作为签发时间
                .expiration(expiration) // 过期时间
                .signWith(secretKey,Jwts.SIG.HS256)
                // ... 可以追加更多的参数 ...
                .compact();//生成签名

        System.out.println(jwt);

生成结果

eyJraWQiOiJhS2V5SWQiLCJLZXkiOiJWYWx1ZSIsImtleSI6InYiLCJhbGciOiJub25lIn0.eyJzdWIiOiJGIiwiaW1nIjoiMTIzLnBuZyIsInVybCI6Imh0dHBzOi8veHh4LmNvbSIsInVzZXJuYW1lIjoiRmVuZyIsInVzZXJpZCI6ImVxZXh0YTkzOWMiLCJpYXQiOjE3MDA3MDcyNDgsImV4cCI6MTcwMDcwNzk0OH0.

JWT验证签名

//解密签名   
Jwt<?, ?> parse = Jwts.parser().verifyWith(secretKey).build().parse(jwt);
System.out.println(parse.getHeader().get("Key"));
System.out.println(parse.getPayload().toString());

解密结果

Value
{sub=F, img=123.png, url=https://xxx.com, username=Feng, userid=eqexta939c, iat=1700709148, exp=1700709848}

在不需要头信息的情况下, 使用parseSignedClaims方法更加方便使用

		Jws<Claims> claimsJwt = Jwts.parser()
				                .verifyWith(secretKey)
				                .build()
				                .parseSignedClaims(jwt);
        Claims claimsJwtPayload = claimsJwt.getPayload();

        System.out.println("--------------------------------------");
        System.out.println(claimsJwtPayload.getSubject());
        // 从负载中获取数据
        String username = claimsJwtPayload.get("username", String.class);
        String userid = claimsJwtPayload.get("userid", String.class);
        String img = claimsJwtPayload.get("img", String.class);
        String url = claimsJwtPayload.get("url", String.class);
        String myKey = claimsJwtPayload.get("key", String.class);

        // 打印获取的数据
        System.out.println("Username: " + username);
        System.out.println("User ID: " + userid);
        System.out.println("myKey: " + myKey);
        System.out.println("img: " + img);
        System.out.println("url: " + url);
        System.out.println("Subject : " + claimsJwtPayload.getSubject());
        System.out.println("Expiration : " + claimsJwtPayload.getExpiration());
        System.out.println("IssuedAt : " + claimsJwtPayload.getIssuedAt());

输出结果

F
Username: Feng
User ID: eqexta939c
myKey: null
img: 123.png
url: https://xxx.com
Subject : F
Expiration : Thu Nov 23 11:24:08 CST 2023
IssuedAt : Thu Nov 23 11:12:28 CST 2023

HMAC 签名(Hash-based Message Authentication Code,散列消息认证码)

// 创建一个测试的秘钥  HMAC-SHA :
MacAlgorithm alg = Jwts.SIG.HS512; //or HS384 or HS256
SecretKey key = alg.key().build();

String message = "Hello World!";
byte[] content = message.getBytes(StandardCharsets.UTF_8);

//加密,指定Jwts.SIG.HS512算法加密
String jws = Jwts.builder().content(content, "text/plain")
			.signWith(key, alg).compact();
//解密
content = Jwts.parser().verifyWith(key).build()
			.parseSignedContent(jws).getPayload();

System.out.println(message.equals(new String(content,StandardCharsets.UTF_8)));

RSA 签名

// 使用 RSA 加密算法:
SignatureAlgorithm RSAalg = Jwts.SIG.RS512;//or PS512, RS256, etc...
//创建秘钥
KeyPair pair = RSAalg.keyPair().build();
// 使用私钥加密
String RSAjws = Jwts.builder().subject("Alice")
        .signWith(pair.getPrivate(), RSAalg) // <-- 私钥
        .compact();
// 使用公钥解密
String subject = Jwts.parser()
        .verifyWith(pair.getPublic()) // <-- 公钥
        .build().parseSignedClaims(RSAjws).getPayload().getSubject();
System.out.println( "Alice".equals(subject));

ECDSA 签名(椭圆曲线数字签名算法)

//使用 ECDSA 算法加密:
SignatureAlgorithm ECDSAAlg = Jwts.SIG.ES512; //or ES256 or ES384
//创建秘钥
KeyPair ECDSAPair = ECDSAAlg.keyPair().build();

// 使用私钥加密
String ECDSAJws = Jwts.builder().subject("Alice")
        .signWith(ECDSAPair.getPrivate(), ECDSAAlg) // <-- 私钥
        .compact();

// 使用公钥加密
String ECDSASubject = Jwts.parser()
        .verifyWith(ECDSAPair.getPublic()) // <-- 公钥
        .build().parseSignedClaims(ECDSAJws).getPayload().getSubject();

System.out.println("Alice".equals(ECDSASubject));

EdDSA签名(爱德华兹曲线数字签名算法)

//使用 Ed25519 加密算法:
Curve curve = Jwks.CRV.Ed25519; //or Ed448
//创建秘钥
KeyPair Ed25519pair = curve.keyPair().build();

// 私钥加密
String Ed25519jws = Jwts.builder().subject("Alice")
        .signWith(Ed25519pair.getPrivate(), Jwts.SIG.EdDSA) // <-- 私钥
        .compact();

// 公钥解密
String Ed25519subject = Jwts.parser()
        .verifyWith(Ed25519pair.getPublic()) // <-- 公钥
        .build().parseSignedClaims(Ed25519jws).getPayload().getSubject();

System.out.println("Alice".equals(Ed25519subject)); 

AES签名(对称加密)

//可以生成秘钥或者自定义秘钥,长度参考
SecretKey key = Keys.hmacShaKeyFor("AWEQWEWE23123156qqqq465wqeqweqweqwewqeqweqweqweq4".getBytes(StandardCharsets.UTF_8)); // 你的密钥
String AESSub="xiaoming";
Claims claims1 = Jwts.claims().subject(AESSub)
		.add("username", "ming")
        .add("userid", "exisxxxxc")
        .add("avatar", "https://res.wx.qq.com/a/wx_fed/weixin_portal/res/static/img/1L3ryyg.png").build();
String token = Jwts.builder().claims(claims1)
        .issuedAt(now) // 当前时间作为签发时间
        .expiration(expiration) // 过期时间
        .signWith(key, Jwts.SIG.HS256)//秘钥
        .compact();

Jws<Claims> claimsJws = Jwts.parser()
        .verifyWith(key) // <----秘钥
        .build()
        .parseSignedClaims(token);
System.out.println(AESSub.equals(claimsJws.getPayload().getSubject()));
System.out.println(claimsJws.getPayload());

如果需要加密签名的话,请参考官方文档

链接: JWT

你可能感兴趣的:(java,算法)