最新JJWT 0.12.6学习

本文参考的是jjwt官方github,链接在此,本文会持续跟进jjwt的最新版本
GitHub - jwtk/jjwt: Java JWT: JSON Web Token for Java and Android

简介

JJWT(Java JWT)是Java平台上相当流行的用于生成Json Web Token的库,其更新速度非常快,导致网上许多教程在如今看来都已经过时。本文将对最新的JJWT官方github页进行中文解释,力求做到与官方同步。
最简单的JWT结构由以下两个部分组成:

  1. payload有效负载,是JWT中的主要数据,可以是你想要的任何数据。
  2. header标头。 具有 名称/值 对的JSON对象,表示有关有效负载和消息本身的元数据

上述两个部分由 . 隔开,所以可以给出一个JWT例子:eyJhbGciOiJub25lIn0.VGhlIHRydWUgc2lnbiBvZiBpbnRlbGxpZ2VuY2UgaXMgbm90IGtub3dsZWRnZSBidXQgaW1hZ2luYXRpb24u.
其中:

  1. eyJhbGciOiJub25lIn0是标头(header)
  2. VGhlIHRydWUgc2lnbiBvZiBpbnRlbGxpZ2VuY2UgaXMgbm90IGtub3dsZWRnZSBidXQgaW1hZ2luYXRpb24u是有效负载(payload)

对于JWS来说,会新增一个**签名(signature)**部分。对于JWE来说,则是五个部分JOSE Header、JWE Encrypied Key、Initialization Vector、Ciphertext和Authentication Tag。

名词解释

JWTJava Web Token 一种通用的基于文本的信息传递格式,可用于传递任意类型的数据
JWSJSON Web Signature 对JSON数据结构进行签名的标准,用于确保数据完整和来源的真实性
JWEJSON Web Encryption 对JSON数据结构进行加密的标准,用于确保数据的机密性

JWS和JWE的区别在于,

  1. JWS中的数据是可以被任何人查看的,其只能够保证信息在传递过程中未被篡改;
  2. JWE则保护了数据不被未授权方查看,也能够保证信息未被篡改,因此数据涉及到隐私时应当使用JWE。

声明(Claim)

在许多场景下,开发者习惯使用JSON的有效负载(payload)来表示用户或主机或其他的身份概念的数据。这种情况下的负载(payload)就称为声明(Claim)。大家常用的比如说用户名/ip地址等都可以归属到声明之中。

自定义声明(Custom Claims)

毫无疑问,jjwt也是支持自定义声明的,使用Claim()方法即可在payload中插入自己想要的键值对

快速开始

安装

Maven

<dependency>
  <groupId>io.jsonwebtoken</groupId>
  <artifactId>jjwt-api</artifactId>
  <version>0.12.6</version>
</dependency>
<dependency>
  <groupId>io.jsonwebtoken</groupId>
  <artifactId>jjwt-impl</artifactId>
  <version>0.12.6</version>
  <scope>runtime</scope>
</dependency>
<dependency>
  <groupId>io.jsonwebtoken</groupId>
  <artifactId>jjwt-jackson</artifactId> <!-- or jjwt-gson if Gson is preferred -->
  <version>0.12.6</version>
  <scope>runtime</scope>
</dependency>
<!-- 如果你想要使用接下来的这些功能,请取消注释下面依赖项的注释:
- JDK 10 或更早, 并且你想要使用RSASSA-PSS (PS256, PS384, PS512)签名算法.
- JDK 10 或更早, 并且你想要使用EdECDH (X25519 or X448) Elliptic Curve Diffie-Hellman加密.
- JDK 14 或更早, 并且你想要使用EdDSA (Ed25519 or Ed448) Elliptic Curve签名算法.
对于JDK15或以上的版本来说,这些算法是不必要的.
<dependency>
  <groupId>org.bouncycastle</groupId>
  <artifactId>bcprov-jdk18on</artifactId> or bcprov-jdk15to18 on JDK 7
  <version>1.76</version>
  <scope>runtime</scope>
</dependency>
-->

使用JJWT进行JWS生成

// key生成部分
SecretKey key = Jwts.SIG.HS256.key().build();

//jws生成部分
String jws = Jwts.builder()
    .subject("Joe")
    .claim("name","Mike")	
    .claim("address","Beijing")
    .signWith(key)
    .compact();

key生成部分

首先SecretKey key = Jwts.SIG.HS256.key().build();
image.png
进行调试可以看到,生成的是一个SecertKey对象,包含两个属性:keyalgorithmkey随机生成的一个HMAC密钥,algorithm则说明当前使用的签名算法。需要保管好这个key,后续的jws解析也需要用到它.

jws生成部分

然后是jws生成部分上文生成的的jws是一条JWS,
.claim("name","Mike")指payload中新增一条"name":“Mike"的键值对
.claim("address","Beijing")用于指出claim()方法是可以多次重复使用的
.subject("Joe")指payload中的键sub的值为"Joe”
.signWith(key)指使用生成的key进行签名
.compact()指将其压缩为String格式

使用JJWT进行JWS解析

// jws解析
Jws<Claims> claims= Jwts.parser()
    .verifyWith(key)
    .build()
    .parseSignedClaims(jws);

System.out.println(claims.getPayload().get("sub"));
System.out.println(claims.getPayload().get("name"));
System.out.println(claims.getPayload().get("address"));

.verifyWith(key)指的是选用解析jws用的key,上面用过,此处调用即可
.paraseSignedClaims(jws)指选用jws这个字符串进行解析
得到一个Jws类型的对象claims
claims.getPayload().get("sub")指从payload中获取键"sub"对应的值,另外两个亦然

创建JWT

根据以下步骤创建JWT:

  1. 使用Jwts.builder()方法来创建一个JwtBuilder实例
  2. (可选)根据需求设置header参数
  3. 调用构建器方法来设置有效负载 content **或 **claims
  4. (可选)如果需要对JWT进行数字签名或者加密时,调用signWithencryptWith方法(分别对应JWS和JWE)
  5. 调用compact()方法来生成紧凑的JWT字符串

例如

String jwt = Jwts.builder()                     // (1)

    .header()                                   // (2) 可选
        .keyId("aKeyId")
        .and()

    .subject("Bob")                             // (3) JSON Claims, 或
    //.content(aByteArray, "text/plain")        //     任意字节内容

    .signWith(signingKey)                       // (4) 数字签名, 或
    //.encryptWith(key, keyAlg, encryptionAlg)  //     加密

    .compact();                                 // (5)
  • JWT payload可以是字符数组(使用content方法),也可以是JSON Claims(使用subjectclaims等方法)但是不能同时既是字符数组又是JSON Claims
  • 数字签名(signWith()方法)和加密(encryptWith()方法)同上,不能同时使用

JWT Header

JWT Header 是一个JSON对象,提供有关 内容,格式以及与JWT payload相关的任何加密操作的元数
据。JJWT提供了多种设置整个Header和/或多个单独Header参数(键值对)

JwtBuilder Header

设置你想要的JWT Header参数,最简单的方式就是使用JwtBuilder的header()构建器,然后再调用and()方法返回到JwtBuilder中,配置payload或者是signature部分进行进一步配置,例如

String jwt = Jwts.builder()

    .header()                        // <----
        .keyId("aKeyId")
        .x509Url(aUri)
        .add("someName", anyValue)	//<--- 支持自定义Header
        .add(mapValues)				//<--- 支持输入参数Map
        // ... etc ...
        .and()               // 回到JwtBuilder。.and()可以看作是header部分的结束

    .subject("Joe")          // 继续调用JwtBuilder,可以接着写payload部分了
    // ... etc ...
    .compact();

JwtBuilder()header()构建器也支持自动计算X.509指纹 等其他功能。
小贴士:

  • 自动Header功能:你无需手动设置header中的alg,enczip,JJWT会自动设置(快说谢谢JJWT orz)

Jwts HeaderBuilder

原文中建议的是使用Jwts.Builder进行构建,因此此处我** 暂时 **不翻译,先行翻译比较重要的构建payload部分。

JWT Payload

JWT的payload可以是任何内容——任何可以表示为 字节数组 的内容,例如文本、图像、文档等等。但由于JWT header总是JSON格式,因此payload也可以是JSON,特别是用于表示身份声明(也就是Claim)。
因此,JwtBuilder支持两种不同的payload选项:

  • content:如果您希望payload是任意 字节数组 内容
  • Claims(以及支持的其他辅助方法):如果您希望payload是一个JSON Claims Object。

这两种选项可以使用任意一种,但 不能同时使用!!!!!。同时使用会导致compact()抛出异常。

任意内容

你可以使用JwtBuilder中的content()方法将payload设置为任意内容,需要注意的是,只有最后一次调用的content()方法会生效。例如

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

String jwt = Jwts.builder()

    .content(content, "text/plain") //<--- 任意内容,第二个参数会设置为header中的cty
    .content(content) 				//<--- 同样是任意内容,第二个参数可以不写
    .content(content)				//<--- 只有这个content会生效
    
    // ... etc ...

    .build();

给个案例吧,官方有点啰嗦

String jws = Jwts.builder()
    .content("你好呀,祝你开心哈哈","你好你好")
    .content("早上好中午好晚上好")
    .content("哈哈哈","cty是哈哈哈")
    .signWith(key)
    .compact();

解析出来的jwt结果是

Header{
  "cty": "cty是哈哈哈",
  "alg": "HS256"
}
Payload:
哈哈哈

很明显,最后只有.content("哈哈哈","cty是哈哈哈")这一行生效了。
第二个参数的标准写法参照RFC 7515: JSON Web Signature (JWS)。官方 强烈推荐使用 双参数方法,因为可以让接收者便利的知晓 payload 中数据的格式。

JWT Claims

JWT payload可能会包含JWT接收者的断言或者是身份认证信息,而不是字符数组内容。在这种情况下,payload就是一个 Claims JSON Object

Standard Claims(标准声明)

在RFC7519标准中,存在着数个标准声明(standard claim)。这些Claims并非强制性要求。JJWT为每一个标准声明都提供了方便的构造方法。例如subject()iss()等方法。标准声明表:

举个栗子:

String jws = Jwts.builder()

    .issuer("me")
    .subject("Bob")
    .audience().add("you").and()
    .expiration(expiration) //java.util.Date类
    .notBefore(notBefore) //java.util.Date类
    .issuedAt(new Date()) // 当前时间
    .id(UUID.randomUUID().toString()) //示例id

    /// ... etc ...
自定义Claims

如果你需要设置和上面不一样的自定义声明,你可以使用JwtBuilder的claim()方法,可以使用多次,每使用一次都会向payload中新增一个键-值对。

String jws = Jwts.builder()
    .claim("hello", "world")
    .claim("你好", "我好") 
    // ... etc ...

当然,你也可以直接往payload里面加入Map

Map<String,?> claims = getMyClaimsMap(); //implement me

String jws = Jwts.builder()
    .claims(claims)
    // ... etc ...

JWT 压缩

未完待续....

2024/07/16日记:本来没啥状态,甚至跑出去干了一瓶啤酒,结果晚上回宿舍坐在电脑前没事做,就鬼使神差打开csdn写这玩意了。。。。

  • 17
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
Spring Boot JJWT (JSON Web Token) 是一个用于在 Spring Boot 应用程序中实现 JWT 的库。JWT 是一种用于安全传输信息的开放标准(RFC 7519),它通过数字签名验证数据的完整性,并使用密钥对数据进行加密。 要在 Spring Boot 中使用 JJWT,您需要添加相关的依赖项到您的项目中。可以通过 Maven 或 Gradle 将以下依赖项添加到您的构建文件中: Maven 依赖项: ```xml <dependency> <groupId>io.jsonwebtoken</groupId> <artifactId>jjwt-api</artifactId> <version>0.11.2</version> </dependency> <dependency> <groupId>io.jsonwebtoken</groupId> <artifactId>jjwt-impl</artifactId> <version>0.11.2</version> <scope>runtime</scope> </dependency> <dependency> <groupId>io.jsonwebtoken</groupId> <artifactId>jjwt-jackson</artifactId> <version>0.11.2</version> <scope>runtime</scope> </dependency> ``` Gradle 依赖项: ``` implementation 'io.jsonwebtoken:jjwt-api:0.11.2' runtimeOnly 'io.jsonwebtoken:jjwt-impl:0.11.2' runtimeOnly 'io.jsonwebtoken:jjwt-jackson:0.11.2' ``` 完成后,您可以开始在 Spring Boot 应用程序中使用 JJWT 来创建和验证 JWT。您可以使用 JJWT 的 `Jwts` 类来创建和解析 JWT。 例如,要创建一个 JWT,您可以使用以下代码: ```java import io.jsonwebtoken.Jwts; import io.jsonwebtoken.SignatureAlgorithm; String secretKey = "yourSecretKey"; String jwt = Jwts.builder() .setSubject("username") .signWith(SignatureAlgorithm.HS256, secretKey) .compact(); ``` 要解析和验证 JWT,您可以使用以下代码: ```java import io.jsonwebtoken.Claims; import io.jsonwebtoken.Jwts; String jwt = "yourJWT"; String secretKey = "yourSecretKey"; Claims claims = Jwts.parser() .setSigningKey(secretKey) .parseClaimsJws(jwt) .getBody(); String username = claims.getSubject(); ``` 这只是 JJWT 的基本用法示例,您还可以使用 JJWT 来处理更复杂的 JWT 操作,如设置过期时间、添加自定义声明等。 希望这能帮到你!如果有其他问题,请随时问我。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值