JWT如何解析过期的token中的信息

本文涉及的产品
云数据库 Redis 版,标准版 2GB
推荐场景:
搭建游戏排行榜
云原生内存数据库 Tair,内存型 2GB
云解析 DNS,旗舰版 1个月
简介: JWT如何解析过期的token中的信息

 一、问题背景

  最近搭建springcloud的项目,项目采取了Jwt + spring security 来进行登录验证,Jwt token 锁定用户的失效时间,但是由于 jwt token特性导致token失效时间无法刷新,所以必须新创建一个token令牌,用来代替之前已失效token。

  (token失效时间无法刷新的原因是由于jwt创建token是根据jwt保存的相关信息来计算的,过期时间是其中的一个计算维度,所以一旦过期时间改了,那么生成的token值也就变了。)

  之后为了解决这个问题,结合了redis,将token值保存到redis中,用户操作后刷新redis的有效时间,这样如果jwt token失效了,再检查 redis 中保存token的key是否失效,如果没有失效,那么就重新创建jwt token ,失效了,就重新登录。

  我用一个过期token去调用接口,返回请求未授权。我查看token拦截的方法,发现是token解析异常,返回null导致接口返回未授权。token解析的最终处理都是parseJWT(jsonWebToken)这个方法,代码如下:

public static Claims parseJWT(String jsonWebToken) {
        try {
            return Jwts.parser().setSigningKey(Base64.getDecoder().decode(getBase64Security())).parseClaimsJws(jsonWebToken).getBody();
        } catch (Exception var2) {
            return null;
        }
    }

image.gif

二、问题原因

根据报错堆栈信息找到了DefaultJwtParser类中,找到了问题的原因。

传入过期token,debug调试发现是在DefaultJwtParser的parse(String jwt)方法中返回了ExpiredJwtException 过期异常。部分代码如下

boolean allowSkew = this.allowedClockSkewMillis > 0L;
                if (claims != null) {
                    Date now = this.clock.now();
                    long nowTime = now.getTime();
                    Date exp = claims.getExpiration();
                    String nbfVal;
                    SimpleDateFormat sdf;
                    if (exp != null) {
                        long maxTime = nowTime - this.allowedClockSkewMillis;
                        Date max = allowSkew ? new Date(maxTime) : now;
                        if (max.after(exp)) {
                            sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");
                            String expVal = sdf.format(exp);
                            nbfVal = sdf.format(now);
                            long differenceMillis = maxTime - exp.getTime();
                            String msg = "JWT expired at " + expVal + ". Current time: " + nbfVal + ", a difference of " + differenceMillis + " milliseconds.  Allowed clock skew: " + this.allowedClockSkewMillis + " milliseconds.";
                            throw new ExpiredJwtException((Header)header, claims, msg);
                        }
                    }
                    Date nbf = claims.getNotBefore();
                    if (nbf != null) {
                        long minTime = nowTime + this.allowedClockSkewMillis;
                        Date min = allowSkew ? new Date(minTime) : now;
                        if (min.before(nbf)) {
                            sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");
                            nbfVal = sdf.format(nbf);
                            String nowVal = sdf.format(now);
                            long differenceMillis = nbf.getTime() - minTime;
                            String msg = "JWT must not be accepted before " + nbfVal + ". Current time: " + nowVal + ", a difference of " + differenceMillis + " milliseconds.  Allowed clock skew: " + this.allowedClockSkewMillis + " milliseconds.";
                            throw new PrematureJwtException((Header)header, claims, msg);
                        }
                    }
                    this.validateExpectedClaims((Header)header, claims);
                }

image.gif

看到结尾的throw new ExpiredJwtException,我相信就找到了问题的关键,原来在在解析token并发现这个token已经过期了,它作出的反应是直接抛异常。

image.gif编辑

异常定义的构造方法中除了msg信息,还有claims和header信息。

检查claims发现,在异常之前token其实已经解析完毕。

这样也就代表着,抛出的这个异常 ExpiredJwtException 中有一个参数 claims 就是解析后的token,那么本次这个问题也就解决了。

  catch ExpiredJwtException 异常后,直接从异常中获取解析的数据即可。

三、方法处理

修改原来的parseJWT(jsonWebToken),代码如下:

public static Claims parseJWT(String jsonWebToken) {
        try {
            return Jwts.parser().setSigningKey(Base64.getDecoder().decode(getBase64Security())).parseClaimsJws(jsonWebToken).getBody();
        } catch (ExpiredJwtException var) {
            return  var.getClaims();
        } catch (PrematureJwtException var1) {
            return var1.getClaims();
        } catch (Exception var2) {
            return null;
        }
    }

image.gif

ExpiredJwtException 异常是超过token过期时间异常

PrematureJwtException 异常是早于token生效时间异议

附带判断token是否过期的方法代码:

public Boolean isTokenExpired(String token) {
        //不管是否过期,都返回claims对象
        Claims claims = parseJWT(token);
        Date expiration = claims.getExpiration();
        //和当前时间进行对比来判断是否过期
        return new Date(System.currentTimeMillis()).after(expiration);
    }

image.gif

最终测试,可以从过期的token中获取用户信息了,接口也不拦截过期token了(因为之间的拦截器代码是根据token能不能解析用户信息去拦截的)。


相关文章
|
26天前
|
JavaScript API 数据安全/隐私保护
【Azure Developer】Azure AD 注册应用的 OAuth 2.0 v2 终结点获取的 Token 解析出来依旧为v1, 这是什么情况!
【Azure Developer】Azure AD 注册应用的 OAuth 2.0 v2 终结点获取的 Token 解析出来依旧为v1, 这是什么情况!
|
1月前
|
存储 JSON JavaScript
震撼!Cookie、Session、Token、JWT 终极对决:揭开 Web 认证的神秘面纱!
【8月更文挑战第13天】Web 开发中,Cookie、Session、Token 和 JWT 常混淆。Cookie 是服务器给客户端的小信息片,如登录状态,每次请求都会返回。Session 则是服务器存储的用户数据,通过 Session ID 追踪。Token 类似通行证,证明客户端身份且可加密。JWT 是结构化的 Token,含头部、载荷及签名,确保数据完整性和安全性。
39 4
|
1月前
|
网络协议 网络安全
DNS信息收集详解
DNS信息收集详解
25 1
|
26天前
|
API
【Azure Developer】记录一段验证AAD JWT Token时需要设置代理获取openid-configuration内容
【Azure Developer】记录一段验证AAD JWT Token时需要设置代理获取openid-configuration内容
|
27天前
|
JSON Java API
【Azure Developer】如何验证 Azure AD的JWT Token (JSON Web 令牌)?
【Azure Developer】如何验证 Azure AD的JWT Token (JSON Web 令牌)?
|
27天前
|
JSON 算法 API
【Azure API 管理】APIM 配置Validate-JWT策略,验证RS256非对称(公钥/私钥)加密的Token
【Azure API 管理】APIM 配置Validate-JWT策略,验证RS256非对称(公钥/私钥)加密的Token
|
2月前
|
数据采集 分布式计算 DataWorks
DataWorks产品使用合集之任务工作流中遇到了日志信息显示参数值没有正确解析的问题,该如何处理
DataWorks作为一站式的数据开发与治理平台,提供了从数据采集、清洗、开发、调度、服务化、质量监控到安全管理的全套解决方案,帮助企业构建高效、规范、安全的大数据处理体系。以下是对DataWorks产品使用合集的概述,涵盖数据处理的各个环节。
|
1月前
|
安全 Nacos 数据安全/隐私保护
【技术干货】破解Nacos安全隐患:连接用户名与密码明文传输!掌握HTTPS、JWT与OAuth2.0加密秘籍,打造坚不可摧的微服务注册与配置中心!从原理到实践,全方位解析如何构建安全防护体系,让您从此告别数据泄露风险!
【8月更文挑战第15天】Nacos是一款广受好评的微服务注册与配置中心,但其连接用户名和密码的明文传输成为安全隐患。本文探讨加密策略提升安全性。首先介绍明文传输风险,随后对比三种加密方案:HTTPS简化数据保护;JWT令牌减少凭证传输,适配分布式环境;OAuth2.0增强安全,支持多授权模式。每种方案各有千秋,开发者需根据具体需求选择最佳实践,确保服务安全稳定运行。
79 0
|
1月前
|
存储 开发框架 JSON
ASP.NET Core 标识(Identity)框架系列(二):使用标识(Identity)框架生成 JWT Token
ASP.NET Core 标识(Identity)框架系列(二):使用标识(Identity)框架生成 JWT Token
|
1月前
|
Java Spring
JWT token验证后,通过 ThreadLocal 进行传值
JWT token验证后,通过 ThreadLocal 进行传值
14 0

热门文章

最新文章

推荐镜像

更多