您的位置:

JWT工具类详解

一、JWT简介

JWT全称为Json Web Token(JSON Web Token),主要用于网络上信息的传输,也可以用于其他场合。JWT由3部分组成,分别是头部(header)、载荷(payload)和签名(signature)。头部和载荷都是JSON格式的信息,签名是用于验证数据完整性的一串字符。使用JWT可以有效地避免在传输过程中被篡改的风险,同时也可以提高网络传输效率。

二、JWT工具类的实现原理

JWT工具类通过封装实现了jwt的生成和验证。一个JWT实际上由3部分组成,即头部、载荷和签名,而这3部分都是由Base64编码后的JSON字符串。首先,我们需要指定签名的算法和密钥。对于头部和载荷部分,我们需要指定信息类型及传输的数据。具体而言,我们需要 RFC7519 规范中的一个例子:

{
  "alg": "HS256",
  "typ": "JWT"
}
{
  "sub": "1234567890",
  "name": "Peter Smith",
  "iat": 1516239022
}

上面是一个头部和载荷都包含的例子。在生成JWT时,我们需要通过指定这些信息和密钥来生成签名,并将签名拼接到头部和载荷后形成一个完整的JWT内容。

import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jws;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import io.jsonwebtoken.security.Keys;
import org.apache.commons.codec.binary.Base64;

import javax.crypto.SecretKey;
import java.security.Key;
import java.util.Date;

public class JwtUtil {

    private static final long EXPIRATION_TIME = 3600_000; // 1小时
    private static final Key SECRET = Keys.secretKeyFor(SignatureAlgorithm.HS256);

    /**
     * 生成JWT
     *
     * @param subject 认证主体
     * @return JWT
     */
    public static String generateToken(String subject) {
        Date now = new Date();
        Date expiration = new Date(now.getTime() + EXPIRATION_TIME);

        return Jwts.builder()
                .setIssuer("JwtUtil")
                .setSubject(subject)
                .setIssuedAt(now)
                .setExpiration(expiration)
                .signWith(SECRET)
                .compact();
    }

    /**
     * 解析JWT
     *
     * @param jwt JWT内容
     * @return 令牌声明
     */
    public static Claims parseToken(String jwt) {
        if (jwt == null) {
            return null;
        }

        String[] parts = jwt.split("\\.");
        if (parts.length != 3) {
            return null;
        }

        byte[] bytes = Base64.decodeBase64(parts[0]);
        String headerJson = new String(bytes);

        bytes = Base64.decodeBase64(parts[1]);
        String payloadJson = new String(bytes);

        byte[] signature = Base64.decodeBase64(parts[2]);

        Jws jwtClaims = Jwts.parserBuilder()
                .setSigningKey(SECRET)
                .build()
                .parseClaimsJws(jwt);

        return jwtClaims.getBody();
    }
}

  

三、JWT工具类的应用示例

使用JWT工具类生成和解析一条JWT内容非常简单。首先,我们需要调用生成令牌的方法,传入认证主体的信息即可。比如,以下代码生成了一个认证主体为"johndoe"的JWT:

String jwt = JwtUtil.generateToken("johndoe");

生成的JWT如下:

eyJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJKd3RVbHQiLCJzdWIiOiJqb2huZG9lIiwiaWF0IjoxNjE2NDM1NDk2LCJleHAiOjE2MTY0Mzk0OTZ9.97WXEWl-9v_9-mMpJlav8Qoyx5lEhrnbZm8F5ZkT9uA

其间包含头部、载荷和签名三部分。

接着,我们可以使用JWT工具类的解析方法将JWT解析成认证主体内容。比如,以下代码将jwt解析为Claims:

Claims claims = JwtUtil.parseToken(jwt);

解析后的结果如下:

{
  "iss": "JwtUtil",
  "sub": "johndoe",
  "iat": 1616435496,
  "exp": 1616439496
}

四、JWT工具类的优缺点

优点

JWT工具类的优点主要包括以下几个方面:

1. 简化处理

JWT工具类封装了JWT的生成和解析过程,使得使用者可以不必了解JWT的细节就可以轻松实现JWT功能。

2. 安全性高

JWT工具类实现了签名的生成和验证过程,通过指定签名算法和密钥可以有效地避免信息在传输过程中被篡改的风险,保证了信息传输的安全性。

缺点

JWT工具类的缺点主要体现在以下几个方面:

1. 客户端存储问题

由于JWT是无状态的,因此在认证过程中需要将所有的信息都包含在JWT中,这就使得JWT变得较为臃肿。同时,JWT也需要被存储于客户端,如果存储在cookie中,就容易受到 CSRF(跨站请求伪造)的攻击;而如果存储在localStorage中,则容易受到 XSS(跨站脚本攻击)的攻击。

2. 无效验证问题

由于JWT是无状态的,一旦签发后,就无法使其失效。即使将JWT存储在数据库或者Redis中,也只能通过删除来使其失效,而这样往往需要对数据库或者Redis进行频繁的访问和更新,影响系统的效率。

五、总结

JWT工具类是实现JWT功能的重要工具。通过对JWT工具类的详细阐述,我们可以了解到JWT的实现原理和如何应用于具体场景。同时,我们也需要注意到JWT工具类的优缺点,避免在使用JWT工具类时出现问题。