JWT工具类

在此封装一个jwt加密和解密的工具类。具体图下:

public class JwtUtils {

    /**
     * 创建JWT令牌
     * @param id 令牌ID,用于唯一标识令牌
     * @param subject 主题,可以是JSON数据,尽量保持简洁,用于描述令牌的内容
     * @param ttlMillis 令牌有效期(毫秒),指定令牌的过期时间
     * @return 生成的JWT令牌,包含了签名和声明信息
     */
    public static String createJWT(String id, String subject, long ttlMillis) {
        SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256; // 使用HS256算法进行签名
        long nowMillis = System.currentTimeMillis(); // 获取当前时间的毫秒数
        Date now = new Date(nowMillis); // 将当前时间转换为Date对象
        SecretKey secretKey = generalKey(); // 生成密钥
        JwtBuilder builder = Jwts.builder()
                .setId(id) // 设置令牌ID
                .setSubject(subject) // 设置令牌主题
                .setIssuer("Java1234") // 设置令牌签发者
                .setIssuedAt(now) // 设置令牌签发时间
                .signWith(signatureAlgorithm, secretKey); // 使用指定的签名算法和密钥进行签名
        if (ttlMillis >= 0) {
            long expMillis = nowMillis + ttlMillis; // 计算令牌过期时间的毫秒数
            Date expDate = new Date(expMillis); // 将过期时间转换为Date对象
            builder.setExpiration(expDate); // 设置令牌过期时间
        }
        return builder.compact(); // 生成并返回JWT令牌的字符串表示形式
    }

    /**
     * 验证JWT
     * @param jwtStr JWT字符串
     * @return 验证结果
     */
    public static CheckResult validateJWT(String jwtStr) {
        //new一个JWT验证信息的实体对象
        CheckResult checkResult = new CheckResult();
        //Claims类的是表示JWT令牌中的声明信息。
        // Claims类提供了一组方法来获取和设置这些声明信息,使得在验证和处理JWT令牌时更加方便。
        Claims claims = null;
        try {
            // 解析JWT令牌,获取其中的声明信息
            claims = parseJWT(jwtStr);
            // 设置验证结果为成功,并将声明信息设置到验证结果中
            checkResult.setSuccess(true);
            checkResult.setClaims(claims);
        } catch (ExpiredJwtException e) {
            // JWT令牌过期异常,设置错误代码为JWT_ERRCODE_EXPIRE,验证结果为失败
            checkResult.setErrCode(SystemConstant.JWT_ERRCODE_EXPIRE);
            checkResult.setSuccess(false);
        } catch (SignatureException e) {
            // 签名验证失败异常,设置错误代码为JWT_ERRCODE_FAIL,验证结果为失败
            checkResult.setErrCode(SystemConstant.JWT_ERRCODE_FAIL);
            checkResult.setSuccess(false);
        } catch (Exception e) {
            // 其他异常,设置错误代码为JWT_ERRCODE_FAIL,验证结果为失败
            checkResult.setErrCode(SystemConstant.JWT_ERRCODE_FAIL);
            checkResult.setSuccess(false);
        }
        return checkResult;
    }

    /**
     * 生成加密Key
     * @return
     */
    public static SecretKey generalKey() {
        //从系统常量中获取Base64编码的密钥字符串,并解码为字节数组。
        byte[] encodedKey = Base64.decode(SystemConstant.JWT_SECERT);
        //使用解码后的字节数组生成AES算法的密钥。
        SecretKey key = new SecretKeySpec(encodedKey, 0, encodedKey.length, "AES");
        return key;
    }


    /**
     * 解析JWT令牌,获取其中的声明信息
     * @param jwt JWT令牌
     * @return 解析后的声明信息
     * @throws Exception 解析过程中的异常
     */
    public static Claims parseJWT(String jwt) throws Exception {
        // 生成密钥
        SecretKey secretKey = generalKey();
        // 使用密钥解析JWT令牌,并获取其中的声明信息
        return Jwts.parser()
                .setSigningKey(secretKey)
                .parseClaimsJws(jwt)
                .getBody();
    }
	//测试
    public static void main(String[] args) throws InterruptedException {
        //小明失效 10s
        String sc = createJWT("1","小明", 60 * 60 * 1000);
        System.out.println(sc);
        System.out.println(validateJWT(sc).getErrCode());
        System.out.println(validateJWT(sc).getClaims().getId());
        System.out.println(validateJWT(sc).getClaims().getSubject());
        //Thread.sleep(3000);
        System.out.println(validateJWT(sc).getClaims());
        Claims claims = validateJWT(sc).getClaims();
        String sc2 = createJWT(claims.getId(),claims.getSubject(), SystemConstant.JWT_TTL);
        System.out.println(sc2);
    }

}

其中SystemConstant类为封装的超时时间等系统级静态变量信息。

public class SystemConstant {

    /**
     * token
     */
    public static final int JWT_ERRCODE_NULL = 4000;			//Token不存在
    public static final int JWT_ERRCODE_EXPIRE = 4001;			//Token过期
    public static final int JWT_ERRCODE_FAIL = 4002;			//验证不通过

    /**
     * JWT
     */
    public static final String JWT_SECERT = "8677df7fc3a34e26a61c034d5ec8245d";			//密匙
    public static final long JWT_TTL = 24*60 * 60 * 1000;									//token有效时间
}
### JWT 工具类实现示例 以下是基于 JavaJWT 工具类实现示例,该工具类支持创建和解析 JSON Web Token (JWT),并提供了签名验证功能以防止篡改[^2]。 ```java import io.jsonwebtoken.*; import java.util.Date; import java.util.Map; public class JwtUtils { private static final String SECRET_KEY = "your_secret_key"; // 替换为实际使用的密钥 /** * 创建 JWT * * @param claims 自定义载荷数据 * @param ttlMillis 过期时间(毫秒) * @return JWT 字符串 */ public static String createJwt(Map<String, Object> claims, long ttlMillis) { SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256; long nowMillis = System.currentTimeMillis(); Date now = new Date(nowMillis); return Jwts.builder() .setClaims(claims) // 设置自定义载荷 .setIssuedAt(now) // 设置签发时间 .setExpiration(new Date(nowMillis + ttlMillis)) // 设置过期时间 .signWith(signatureAlgorithm, SECRET_KEY.getBytes()) // 使用 HMAC 签名算法和密钥进行签名 .compact(); } /** * 解析 JWT 并返回其中的 Claims 数据 * * @param jwtToken 待解析的 JWT 字符串 * @return Claims 对象 * @throws ExpiredJwtException 如果令牌已过期则抛出异常 * @throws UnsupportedJwtException 如果不支持当前令牌类型则抛出异常 * @throws MalformedJwtException 如果令牌格式错误则抛出异常 * @throws SignatureException 如果签名验证失败则抛出异常 */ public static Claims parseJwt(String jwtToken) throws JwtException { return Jwts.parserBuilder() .setSigningKey(SECRET_KEY.getBytes()) .build() .parseClaimsJws(jwtToken) .getBody(); } } ``` 上述代码实现了两个核心方法: 1. **`createJwt` 方法**:用于生成带有指定有效时间和自定义载荷的 JWT。通过 `SignatureAlgorithm.HS256` 和预设的密钥对生成的令牌进行签名,从而确保其不可被随意篡改。 2. **`parseJwt` 方法**:用于解析传入的 JWT,并提取其中的 Claims 数据。如果令牌已经过期、格式非法或者签名验证失败,则会分别抛出对应的异常[^3]。 --- ### 防止 JWT 被篡改的关键机制 为了防止 JWT 被恶意修改或伪造,在生成 JWT 时会对整个头部和载荷部分计算哈希值,并将其作为签名附加到最终的字符串中。当接收方收到此令牌后,可以通过相同的密钥重新计算签名并与原始签名对比来验证其真实性。 例如,在上面的 `parseJwt` 方法中,调用了 `.setSigningKey(SECRET_KEY.getBytes())` 来设置解码所需的密钥。只有持有相同密钥的一方才能够成功完成校验过程;任何试图更改负载内容的行为都会破坏原有的签名结构,进而导致验证失败。 --- ### 测试 JWT 的有效期 下面展示了一个简单的单元测试用例,演示如何利用前面提到的工具类检测某个特定时间段内的 token 是否仍然可用: ```java @Test public void testJwtValidityPeriod() throws Exception { Map<String, Object> claims = Map.of("username", "testUser"); // 创建一个仅持续三秒钟的有效令牌 String shortLivedJwt = JwtUtils.createJwt(claims, 3_000L); Thread.sleep(4_000); // 让线程休眠超过设定时限 try { JwtUtils.parseJwt(shortLivedJwt); fail("Expected an exception due to expired token."); } catch (ExpiredJwtException e) { System.out.println("Caught expected expiration error: " + e.getMessage()); } } ``` 在此例子中,我们故意让程序等待超出预期存活周期后再尝试解读刚才生产的短命凭证。不出所料的话,应该触发相应的超时期限警告消息。 --- ####
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值