关于JWT设置过期时间无效的问题

一、项目场景

项目中需要使用到 JWT 来完成用户身份信息的认证


二、问题描述

使用 JWT 时设置过期时间无效
发现如果先调用 setExpiration 方法再调用 setClaims 方法,则会出现使用 JWT 设置过期时间无效的问题

Jwts.builder()
                .setId(UUID.randomUUID().toString())
                .setIssuedAt(new Date())
                .compressWith(CompressionCodecs.GZIP)
                .signWith(KEY, SignatureAlgorithm.HS512)
                .setExpiration(new Date(currentTimeMillis + TOKEN_EXPIRATION_TIME_MILLIS))
                .setClaims(claims)
                .compact();

而如果先调用 setClaims 方法再调用 setExpiration 方法,则不会出现该问题

 Jwts.builder()
                .setId(UUID.randomUUID().toString())
                .setIssuedAt(new Date())
                .compressWith(CompressionCodecs.GZIP)
                .signWith(KEY, SignatureAlgorithm.HS512)
                .setClaims(claims)
                .setExpiration(new Date(currentTimeMillis + TOKEN_EXPIRATION_TIME_MILLIS))
                .compact();

三、原因分析

查看 setExpiration 方法的源码,当我们设置了过期时间时 exp != null ,这时会走到 ensureClaims().setExpiration(exp);

@Override
public JwtBuilder setExpiration(Date exp) {
    if (exp != null) {
        ensureClaims().setExpiration(exp);
    } else {
        if (this.claims != null) {
            //noinspection ConstantConditions
            this.claims.setExpiration(exp);
        }
    }
    return this;
}

然后再查看 ensureClaims 方法的源码可以发现,如果我们没有事先设置 claims ,那么在这里会产生一个 DefaultClaims 对象赋值给 DefaultJwtBuilder 类的 claims 属性,这个对象将调用 setExpiration(exp) 方法设置过期时间

protected Claims ensureClaims() {
    if (this.claims == null) {
        this.claims = new DefaultClaims();
    }
    return this.claims;
}

但如果在这之后我们再调用 setClaims 方法,那么我们新设置的 claims 将重新赋值到 DefaultJwtBuilder 类的 claims 属性

 @Override
public JwtBuilder setClaims(Map<String, ?> claims) {
    this.claims = new DefaultClaims(claims);
    return this;
}

此时新构造出来的 DefaultClaims 对象没有进行设置过期时间的操作,这也就导致了最后生成的 token 没有过期时间
另一方面,setId 方法和 setIssuedAt 方法的源码跟上面 setExpiration 的源码类似,所以 setId 方法和 setIssuedAt 方法也应该在调用 setClaims 方法后再进行调用

@Override
    public JwtBuilder setId(String jti) {
        if (Strings.hasText(jti)) {
            ensureClaims().setId(jti);
        } else {
            if (this.claims != null) {
                claims.setId(jti);
            }
        }
        return this;
    }
@Override
    public JwtBuilder setIssuedAt(Date iat) {
        if (iat != null) {
            ensureClaims().setIssuedAt(iat);
        } else {
            if (this.claims != null) {
                //noinspection ConstantConditions
                this.claims.setIssuedAt(iat);
            }
        }
        return this;
    }

四、解决方案

生成 JWT 时应该最先调用 setClaims 方法再调用其他的 setXXX 方法

Jwts.builder()
                .setClaims(claims)
                .setId(UUID.randomUUID().toString())
                .setIssuedAt(new Date())
                .compressWith(CompressionCodecs.GZIP)
                .signWith(KEY, SignatureAlgorithm.HS512)
                .setExpiration(new Date(currentTimeMillis + TOKEN_EXPIRATION_TIME_MILLIS))
                .compact();
  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值