java - 如何延长过期时间java json web token?

Posted

技术标签:

【中文标题】java - 如何延长过期时间java json web token?【英文标题】:How to extend expiration time java json web token? 【发布时间】:2015-06-26 23:19:31 【问题描述】:

我尝试使用 jjwt library 在 Java 中创建 Json Web Token

但是当我尝试延长过期时间时遇到问题。

我用下面的代码试试。

public class Main 
public static void main(String args[]) 
    byte[] key = new byte[64];
    new SecureRandom().nextBytes(key);
    Date date = new Date();
    long t = date.getTime();
    Date expirationTime = new Date(t + 5000l); // set 5 seconds

    String compact = Jwts.builder().setSubject("Joe").setExpiration(expirationTime).signWith(SignatureAlgorithm.HS256, key).compact();
    System.out.println("compact : " + compact);
    try 
        String unpack = Jwts.parser().setSigningKey(key).parseClaimsJws(compact).getBody().getSubject();
        System.out.println("unpackage 0 : " + unpack);
        
        // check if the expiration work.
        Thread.sleep(3000);
        System.out.println("unpackage 1 : " + Jwts.parser().setSigningKey(key).parseClaimsJws(compact).getBody().getSubject());
        
        //extend the expration time.
        Date date1 = new Date();
        long t1 = date1.getTime();
        Date expirationTime1 = new Date(t1 + 5000l); //prolongation 5 seconds
        Jwts.parser().setSigningKey(key).parseClaimsJws(compact).getBody().setExpiration(expirationTime1).getSubject();
        
        // check if the extend expiration work.
        Thread.sleep(3000);            
        System.out.println("unpackage 2 : " + Jwts.parser().setSigningKey(key).parseClaimsJws(compact).getBody().getSubject());
     catch (InterruptedException | ExpiredJwtException ex) 
        System.out.println("exception : " + ex.getMessage());
        Thread.currentThread().interrupt();
    

结果是:

紧凑型:eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJKb2UiLCJleHAiOjE0Mjk2NjU1MjB9.oMY2mDHvNoMZqBfic41LbiKvAyi93wIfu_WgIADb9Wc 解包 0:乔 解包1:乔 例外:JWT 于 2015-04-22T08:18:40+0700 过期。当前时间:2015-04-22T08:18:42+0700

也就是说,unpackage2 不能运行,因为已经过期了。

我试图延长过期时间。

因为我将代码应用到网络应用程序上。

如果用户仍然连接到我的应用程序,他不应该得到令牌超时。

我找到了和我一样的another question。

【问题讨论】:

我将您的代码复制并粘贴到单元测试中,并针对 JJWT 0.3 和 0.4 运行它,但无法重现您遇到的问题。可以在运行时粘贴代码的输出吗? 【参考方案1】:

问题出在解析代码上:

Jwts.parser().setSigningKey(key).parseClaimsJws(compact).getBody().setExpiration(expirationTime1).getSubject();

在这一行中,您正在修改解析器返回的 JWT。也就是说,上面等价于这个:

Jws<Claims> jws = Jwts.parser().setSigningKey(key).parseClaimsJws(compact);
jws.getBody().setExpiration(expirationTime1).getSubject();

注意这段代码如何修改解析器返回的 JWT?它不会 - 也不能 - 修改由原始 compact 字符串表示的 JWT。

之后您的下一行代码会尝试解析原始(未修改的)compact String:

// check if the extend expiration work.
Thread.sleep(3000);            
System.out.println("unpackage 2 : " + Jwts.parser().setSigningKey(key).parseClaimsJws(compact).getBody().getSubject());

但我们知道这不会起作用,因为更改解析器返回的 JWT 的状态不会对原始 compact 字符串产生任何影响。

如果您的用户向您的 Web 应用程序提供 JWT,并且您希望“延长令牌的生命周期”使其不会过期,您必须生成新的 JWT 并将该 JWT 发回给用户。用户应该在以后的请求中发回新的 JWT。只要您希望允许用户继续与您的 Web 应用程序对话而无需重新登录,您就可以一直重复此过程。

我应该指出,如果您不想担心这些事情,Stormpath 可以自动为您在浏览器和您的应用程序之间执行用户和 JWT 令牌身份验证 - 您不必构建任何这个自己(披露:我是 Stormpath 的 CTO)。

最后,您可能有兴趣知道 JJWT 的测试套件已经在许多地方验证了过期和过早令牌用例的正确行为:

https://github.com/jwtk/jjwt/blob/0.4/src/test/groovy/io/jsonwebtoken/JwtParserTest.groovy#L163-L189 https://github.com/jwtk/jjwt/blob/0.4/src/test/groovy/io/jsonwebtoken/JwtParserTest.groovy#L307-L335 https://github.com/jwtk/jjwt/blob/0.4/src/test/groovy/io/jsonwebtoken/JwtParserTest.groovy#L421-L454

但是,您不必相信我的话 :) 这是您的代码,已修改,以便您的到期修改功能如所述:

public class Main 

public static void main(String args[]) 
    byte[] key = new byte[64];
    new SecureRandom().nextBytes(key);
    Date date = new Date();
    long t = date.getTime();
    Date expirationTime = new Date(t + 5000l); // set 5 seconds

    String compact = Jwts.builder().setSubject("Joe").setExpiration(expirationTime).signWith(SignatureAlgorithm.HS256, key).compact();
    System.out.println("compact : " + compact);
    try 
        String unpack = Jwts.parser().setSigningKey(key).parseClaimsJws(compact).getBody().getSubject();
        System.out.println("unpackage 0 : " + unpack);

        // check if the expiration work.
        Thread.sleep(3000);
        System.out.println("unpackage 1 : " + Jwts.parser().setSigningKey(key).parseClaimsJws(compact).getBody().getSubject());

        //Create a *new* token that reflects a longer extended expiration time.
        Date date1 = new Date();
        long t1 = date1.getTime();
        Date expirationTime1 = new Date(t1 + 5000l); //prolongation 5 seconds

        String compact2 = Jwts.builder().setSubject("Joe").setExpiration(expirationTime1).signWith(SignatureAlgorithm.HS256, key).compact();

        // check if the extend expiration work.
        Thread.sleep(3000);
        System.out.println("unpackage 2 : " + Jwts.parser().setSigningKey(key).parseClaimsJws(compact2).getBody().getSubject());

        Thread.sleep(1000);
     catch (InterruptedException | ExpiredJwtException ex) 
        System.out.println("exception : " + ex.getMessage());
        Thread.currentThread().interrupt();
    


请注意,需要生成第二个 JWT (compact2) 以反映新的/最新的到期时间。您不能修改已解析的 JWT 并期望更改应用于原始紧凑值。

总之,当您需要解析 JWT 字符串以获得 JWT 的良好 Java 对象表示时,请使用 Jwts.parser()。当您需要创建或修改 JWT 以生成新的紧凑字符串表示时,请使用 Jwts.builder()

希望对你有帮助!

【讨论】:

好的,有没有办法生成新的令牌,只有你手中的过期令牌?所以我想要做的是解析过期的令牌,从它的主体中获取主题(我知道它已经过期,但是它在使用签名密钥检查主体和标题方面是有效的),然后我想使用这个提取的主题来生成有效的授权令牌。谢谢 好的!我得到了它!有一个方法io.jsonwebtoken.ClaimJwtException#getClaims @hsestupin 不,您应该永远信任过期的令牌或未通过签名验证的令牌。 从不。如果你这样做,你就明显违反了 JWT 规范,这是一个黄旗,你需要重新考虑你的设计(你正在尝试做一些应该以不同方式做的事情)。 你好,我不明白下面代码的使用 String unpack1 = Jwts.parser().setSigningKey(key).parseClaimsJws(compact).getBody().getSubject(); System.out.println("解包 0 :" + unpack1); // 检查过期是否有效。线程.sleep(3000); String unpack2 = Jwts.parser().setSigningKey(key).parseClaimsJws(compact).getBody().getSubject(); System.out.println("解包 1 : " +unpack2);

以上是关于java - 如何延长过期时间java json web token?的主要内容,如果未能解决你的问题,请参考以下文章

java网站中session 有默认的过期时间吗?

如何停止延长ajax调用的cookie过期时间?

如何在 Symfony 中延长会话 cookie 的生命周期?

如何在过期前延长asp.net中的会话超时

Laravel 护照延长访问令牌过期时间

java操作Redis缓存设置过期时间