You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何验证JWT令牌的自定义过期时长并手动指定签名算法?

JWT解码与自定义验证问题

我有一段用于解码和验证JWT令牌的Java代码如下:

public class JwtTokenDecoder implements JwtDecoder {

    private String secretKey = "123456789";

    @SneakyThrows
    @Override
    public Jwt decode(String token) throws JwtException {

        JwtParser build = Jwts.parser().verifyWith(getSigningKey()).build();
        io.jsonwebtoken.Jwt<?, ?> parse = build.parse(token);
        Map<String, Object> claims = JsonHelper.jsonMapper().convertValue(parse.getPayload(), new TypeReference<>() {
        });
        claims.put("iat", Instant.ofEpochSecond((long) claims.get("iat")));
        claims.put("exp", Instant.ofEpochSecond((long) claims.get("exp")));
        return Jwt.withTokenValue(token)
                .headers((val) -> val.putAll(parse.getHeader()))
                .claims((val) -> val.putAll(claims))
                .build();
    }

    private SecretKey getSigningKey() {
        byte[] keyBytes = secretKey.getBytes(StandardCharsets.UTF_8);
        return Keys.hmacShaKeyFor(keyBytes);
    }
}

请问如何基于自定义的最小可接受值(例如令牌不超过30天有效期)验证其是否过期,同时手动指定签名算法类型?


解决方案

1. 手动指定签名算法

在构建JwtParser时,通过requireSigningAlgorithm方法明确指定签名算法(如HS256),确保令牌使用预期的算法签名,避免算法混淆类的安全风险。

2. 自定义有效期验证

从JWT的iat(签发时间)字段计算令牌的最大允许有效期,对比当前系统时间,若超出自定义阈值则抛出JwtException;同时可保留默认的exp字段验证,形成双重保障。

修改后的完整代码如下:

import io.jsonwebtoken.*;
import io.jsonwebtoken.security.Keys;
import org.springframework.security.oauth2.jwt.Jwt;
import org.springframework.security.oauth2.jwt.JwtDecoder;
import org.springframework.security.oauth2.jwt.JwtException;
import lombok.SneakyThrows;
import java.nio.charset.StandardCharsets;
import java.time.Instant;
import java.time.temporal.ChronoUnit;
import java.util.Map;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;

public class JwtTokenDecoder implements JwtDecoder {

    private String secretKey = "123456789";
    // 自定义令牌最大有效期:30天
    private static final long MAX_VALID_DAYS = 30;

    @SneakyThrows
    @Override
    public Jwt decode(String token) throws JwtException {
        // 手动指定签名算法为HS256
        JwtParser parser = Jwts.parser()
                .requireSigningAlgorithm(SignatureAlgorithm.HS256.getValue())
                .verifyWith(getSigningKey())
                .build();

        io.jsonwebtoken.Jwt<?, ?> parsedJwt = parser.parse(token);
        Map<String, Object> claims = new ObjectMapper().convertValue(parsedJwt.getPayload(), new TypeReference<>() {});

        // 转换时间字段为Instant类型
        Instant issuedAt = Instant.ofEpochSecond((long) claims.get("iat"));
        Instant expiration = Instant.ofEpochSecond((long) claims.get("exp"));
        claims.put("iat", issuedAt);
        claims.put("exp", expiration);

        // 自定义有效期验证:签发后超过30天则失效
        Instant maxValidTime = issuedAt.plus(MAX_VALID_DAYS, ChronoUnit.DAYS);
        if (Instant.now().isAfter(maxValidTime)) {
            throw new JwtException("令牌已超出自定义最大有效期(30天)");
        }

        // 保留默认过期验证:确保令牌未超过自身设置的exp时间
        if (Instant.now().isAfter(expiration)) {
            throw new ExpiredJwtException(parsedJwt.getHeader(), parsedJwt.getPayload(), "令牌已过期");
        }

        return Jwt.withTokenValue(token)
                .headers(val -> val.putAll(parsedJwt.getHeader()))
                .claims(val -> val.putAll(claims))
                .build();
    }

    private SecretKey getSigningKey() {
        byte[] keyBytes = secretKey.getBytes(StandardCharsets.UTF_8);
        return Keys.hmacShaKeyFor(keyBytes);
    }
}

关键说明

  • 签名算法指定:requireSigningAlgorithm方法强制令牌使用指定算法签名,不符合要求的令牌会直接抛出JwtException,提升安全性。
  • 自定义有效期:通过issuedAt.plus(MAX_VALID_DAYS, ChronoUnit.DAYS)计算令牌允许的最晚使用时间,确保令牌不会被长期滥用。
  • 双重过期验证:同时验证exp字段和自定义有效期,既遵守令牌自身的过期设置,也满足业务侧的有效期限制。

内容的提问来源于stack exchange,提问作者Peter Penzov

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.18 02:00:21