如何使用JJWT及JWT讲解和工具类

作者:枯木何日可逢春 时间:2023-10-28 04:21:35 

1. 什么是JWT

JSON Web Token(JWT)是一个轻量级的认证规范,这个规范允许我们使用JWT在用户和服务器之间传递安全可靠的信息。其本质是一个token,是一种紧凑的URL安全方法,用于在网络通信的双方之间传递。

2. JWT的构成

一个JWT实际上就是一个字符串,它由三部分组成:头部、载荷与签名

2.1 头部(Header)

头部用于描述关于该JWT的最基本的信息,例如其类型以及签名所用的算法等

头部可以被表示成一个JSON对象


{"typ":"JWT","alg":"HS256"}

在头部指明了签名算法是HS256算法。 我们进行BASE64编码,编码后的字符串如下:


eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9



Base64是一种基于64个可打印字符来表示二进制数据的表示方法。


由于2的6次方等于64,所以每6个比特为一个单元,对应某个可打印字符。


三个字节有24个比特,对应于4个Base64单元,即3个字节需要用4个可打印字符来表示。


JDK 中提供了非常方便的 BASE64Encoder 和 BASE64Decoder,用它们可以非常方便的完成基于 BASE64 的编码和解码


2.2 载荷(playload)


载荷是存放有效信息的地方,这些有效信息包含三个部分:


2.2.1 标准中注册的声明(建议但不强制使用)




iss: jwt签发者
sub: jwt所面向的用户
aud: 接收jwt的一方
exp: jwt的过期时间,这个过期时间必须要大于签发时间
nbf: 定义在什么时间之前,该jwt都是不可用的.
iat: jwt的签发时间
jti: jwt的唯一身份标识,主要用来作为一次性token,从而回避重放攻击。

2.2.2 公共的声明

公共的声明可以添加任何的信息,一般添加用户的相关信息或其他业务需要的必要信息。但不建议添加敏感信息,因为该部分在客户端可解密

2.2.3 私有的声明

私有声明是提供者和消费者所共同定义的声明,一般不建议存放敏感信息,因为base64是对称解密的,意味着该部分信息可以归类为明文信息

比如下面举例中的admin和name都属于自定的claim。这些claim跟JWT标准规定的claim区别在于:JWT规定的claim,JWT的接收方在拿到JWT之后,都知道怎么对这些标准的claim进行验证;而private claims不会验证,除非明确告诉接收方要对这些claim进行验证以及验证的规则

定义一个payload:


{"sub":"1234567890","name":"John Doe","admin":true}

然后将其进行base64加密,得到Jwt的第二部分:


eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9

2.3 签证(signature)

JWT的第三部分是一个签证信息,这个签证信息由三部分组成:

header (base64后的)

payload (base64后的)

secret

这个部分需要base64加密后的header和base64加密后的payload使用.连接组成的字符串,然后通过header中声明的加密方式进行加盐secret组合加密,然后就构成了jwt的第三部分:


TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ

将这三部分用.连接成一个完整的字符串,构成了最终的jwt:


eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ

注意:secret是保存在服务器端的,jwt的签发生成也是在服务器端的,secret就是用来进行jwt的签发和jwt的验证,所以secret就是你服务端的私钥,在任何场景都不应该流露出去。一旦客户端得知这个secret, 那就意味着客户端是可以自我签发jwt了

3. JJWT的介绍

JJWT是一个提供端到端的JWT创建和验证的Java库

官方文档:https://github.com/jwtk/jjwt

4. JJWT的使用


<!--鉴权-->
<dependency>
   <groupId>io.jsonwebtoken</groupId>
   <artifactId>jjwt</artifactId>
   <version>0.9.0</version>
</dependency>

import com.sun.scenario.effect.impl.sw.sse.SSEBlend_SRC_OUTPeer;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.JwtBuilder;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import java.util.Date;
import java.util.HashMap;
public class TestJWT {
   public static void main(String[] args) {
       testCreateJWT();
       testParseJWT();
   }
   public static void testCreateJWT() {
       JwtBuilder builder = Jwts.builder()
               .setId("404")                   // 设置唯一编号
               .setSubject("邢立豹")            // 设置主题 可以是JSON数据
               .setIssuedAt(new Date())        // 设置签发日期
               // .setExpiration(new Date())      // 设置过期时间
               // 设置签名 使用HS256算法 并设置SecretKey(字符串)
               .signWith(SignatureAlgorithm.HS256, "LICHUN");
       HashMap<String, Object> userInfo = new HashMap<>();
       userInfo.put("name","枯木何日可逢春");
       userInfo.put("age", "21");
       builder.addClaims(userInfo);
       System.out.println(builder.compact());
   }
   public static void testParseJWT() {
       String str = "eyJhbGciOiJIUzI1NiJ9.eyJqdGkiOiI0MDQiLCJzdWIiOiLpgqLnq4vosbkiLCJpYXQiOjE2MzA2ODAzNTMsImV4cCI6MTYzMDY4MDM1MywibmFtZSI6Iuaer-acqOS9leaXpeWPr-mAouaYpSIsImFnZSI6IjIxIn0.59i5xfLz9A-wTOJI9KxkF7zqp4zsLEWRC5DYlcy_Akc";
       Claims claims = Jwts.parser()
               .setSigningKey("LICHUN")
               .parseClaimsJws(str)
               .getBody();
       System.out.println(claims);
   }
}

5. JWT工具类


package com.lichun.utils;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.JwtBuilder;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import java.util.Base64;
import java.util.Date;
public class JWTUtil {
   // 有效期
   public static final Long JWT_TTL = 3600000L;
   // JWT令牌信息
   public static final String JWT_KEY = "LICHUN";
   public static String createJWT(String id, String subject, Long ttlMillis) {
       SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256;
       long nowMillis = System.currentTimeMillis();
       Date now = new Date(nowMillis);
       if (ttlMillis == null) {
           ttlMillis = JWT_TTL;
       }
       long expMillis = nowMillis + ttlMillis;
       Date expDate = new Date(expMillis);
       SecretKey secretKey = generalKey();
       JwtBuilder builder = Jwts.builder()
               .setId(id)                      // 设置唯一编号
               .setSubject(subject)            // 设置主题 可以是JSON数据
               .setIssuer("admin")
               .setIssuedAt(now)               // 设置签发日期
               .setExpiration(expDate)         // 设置过期时间
               // 设置签名 使用HS256算法 并设置SecretKey(字符串)
               .signWith(SignatureAlgorithm.HS256, secretKey);
       return builder.compact();
   }
   /**
    * 生成加密secretKey
    * @return
    */
   public static SecretKey generalKey() {
       byte[] encodedKey = Base64.getEncoder().encode(JWT_KEY.getBytes());
       SecretKey key = new SecretKeySpec(encodedKey, 0, encodedKey.length, "AES");
       return key;
   }
   /**
    * 解析令牌数据
    */
   public static Claims parseJWT(String jwt) throws Exception {
       SecretKey secretKey = generalKey();
       return Jwts.parser()
               .setSigningKey(secretKey)
               .parseClaimsJws(jwt)
               .getBody();
   }
}

来源:https://blog.csdn.net/weixin_45953673/article/details/120091788

标签:JJWT,JWT,工具类
0
投稿

猜你喜欢

  • Java使用Socket简单通讯详解

    2023-11-03 02:54:43
  • Java将Word文件转为OFD文件

    2023-05-24 01:46:35
  • 用C#缩小照片上传到各种空间的具体方法

    2022-03-28 02:29:18
  • springboot 如何配置多个jndi数据源

    2023-03-13 16:28:07
  • 解决java 分割字符串成数组时,小圆点不能直接进行分割的问题

    2023-11-05 03:13:24
  • SpringCloud整合Nacos实现流程详解

    2021-07-04 11:11:09
  • Unity中协程IEnumerator的使用方法介绍详解

    2023-03-31 13:28:44
  • Android禁止EditText自动弹出软键盘的方法及遇到问题

    2021-07-18 06:35:55
  • Maven配置文件pom.xml详解

    2022-07-03 02:26:43
  • Android App中实现可以双击放大和缩小图片功能的实例

    2023-04-01 16:41:17
  • 详解Spring boot上配置与使用mybatis plus

    2023-02-27 08:53:11
  • Android使用MulticastSocket实现多点广播图片

    2023-01-16 06:13:57
  • 关于Android中drawable必知的一些规则

    2021-08-26 16:24:41
  • Java8 Instant时间戳使用小记

    2023-05-31 10:33:59
  • Gradle学习教程之部署上传项目详解

    2023-08-08 20:46:46
  • Java如何实现压缩文件与解压缩zip文件

    2022-01-28 09:14:00
  • SpringMVC如何用Post方式重定向

    2021-10-05 21:34:27
  • 解决Callable的对象中,用@Autowired注入别的对象失败问题

    2023-11-29 13:23:46
  • Android实现从底部弹出的Dialog示例(一)

    2021-09-12 13:33:09
  • C#绘制时钟的方法

    2021-08-25 15:18:12
  • asp之家 软件编程 m.aspxhome.com