【问题标题】:JWT Token is always received as expired while parsing解析时总是收到 JWT 令牌过期
【发布时间】:2019-04-04 12:08:36
【问题描述】:

我在我的一个应用程序中使用 JWT Authentictaion 以及 Spring Boot/Security,这是我对 JWT 的第一次尝试。

以下是我设置和获取的身份验证方法:

static void addAuthentication(HttpServletResponse res, JWTPayload payload) {
    // all authentication related data like authorities and permissions can be 
    // embed to the token in a map using setClaims()
    Map<String, Object> claims = new HashMap<String, Object>();
    claims.put("roles", payload.getRoles());
    claims.put("permissions", payload.getPermissions());
    String JWT = Jwts.builder()
        .setSubject(payload.getUsername())
        .setClaims(claims)
        .setExpiration(new Date(System.currentTimeMillis() + EXPIRATIONTIME))
        .signWith(SignatureAlgorithm.HS512, SECRET_KEY)
        .compact();
    res.addHeader(HEADER_STRING, TOKEN_PREFIX + " " + JWT);
  }


  /**
   * this method retrives the token from the header and validates it.
   * this method is called from the JWTAuthentication filter which is
   * used against all the incoming calls except the login.
   * @param request
   * @return
   */
  static Authentication getAuthentication(HttpServletRequest request) {
    String token = request.getHeader(HEADER_STRING);
    if (token != null) {
      // parse the token.
      String user = Jwts.parser()
          .setSigningKey(SECRET_KEY)
          .parseClaimsJws(token.replace(TOKEN_PREFIX, ""))
          .getBody()
          .getSubject();

      return user != null ?
          new UsernamePasswordAuthenticationToken(user, null, emptyList()) :
          null;
    }
    return null;
  }

JWT 在标头中生成和接收就好了。但是,如果在后续 API 调用中使用,我会收到以下错误。

io.jsonwebtoken.ExpiredJwtException: JWT expired at 2018-10-31T16:06:05Z. Current time: 2018-10-31T16:06:08Z, a difference of 3421 milliseconds.  Allowed clock skew: 0 milliseconds.

例外情况是允许的时钟偏差为 0 毫秒。在我上面的代码中,EXPIRATIONTIME 设置为 30000(我相信这是以秒为单位设置的)。我也试过增加这个值,但我仍然得到错误。

请指出我做错了什么?

【问题讨论】:

    标签: authentication spring-security jwt


    【解决方案1】:

    不确定您是否已经得到答案,但有人可能会从中受益。最初我遇到了同样的问题,我认为这是 JWT 的问题。但是,当我调试我的代码时,我知道我犯了一个愚蠢的错误,并且过期日期设置在过去。

    因此,为了对此进行测试,我创建了一个可以独立执行的示例程序。检查此项并相应地修改您的代码。希望这会有所帮助。

    import java.security.Key;
    import java.util.Calendar;
    import java.util.HashMap;
    import java.util.Locale;
    import java.util.Map;
    import java.util.UUID;
    
    import javax.crypto.spec.SecretKeySpec;
    import javax.xml.bind.DatatypeConverter;
    
    import io.jsonwebtoken.Claims;
    import io.jsonwebtoken.Jws;
    import io.jsonwebtoken.Jwts;
    import io.jsonwebtoken.SignatureAlgorithm;
    
    public class TestJWTToken {
        private static final String API_KEY = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
    
        public static void main(String... args) {
            String jwt = createJWT();
            System.out.println("JWT: " + jwt);
            parseJWT(jwt);
        }
    
        private static String createJWT() {
            Calendar cal = Calendar.getInstance(Locale.UK);
            Calendar cal1 = Calendar.getInstance(Locale.UK);
            cal1.setTime(cal.getTime());
            cal1.add(Calendar.SECOND, 300);
    
            byte[] apiKeySecretBytes = DatatypeConverter.parseBase64Binary(API_KEY);
            Key signingKey = new SecretKeySpec(apiKeySecretBytes, SignatureAlgorithm.HS256.getJcaName());
    
            Map<String, Object> map = new HashMap<>();
            map.put("alg", "HS256");
            map.put("typ", "JWT");
    
            String someId = UUID.randomUUID().toString();
    
            return Jwts.builder().setHeader(map).setIssuer("service_provider").setSubject("consumer_provider_connectivity_token")
                    .claim("some_id", someId).setIssuedAt(cal.getTime()).setExpiration(cal1.getTime())
                    .signWith(SignatureAlgorithm.HS256, signingKey).compact();
        }
    
        private static void parseJWT(String jwt) {
            Jws<Claims> jwsClaims = Jwts.parser().setSigningKey(DatatypeConverter.parseBase64Binary(API_KEY)).parseClaimsJws(jwt);
            System.out.println("JWT decoded: " + jwsClaims);
    
            Claims claims = jwsClaims.getBody();
            System.out.println("Subject: " + claims.getSubject());
            System.out.println("Issuer: " + claims.getIssuer());
            System.out.println("Issued at: " + claims.getIssuedAt());
            System.out.println("Expiration: " + claims.getExpiration());
            System.out.println("Some_Id: " + claims.get("some_id"));
        }
    }
    

    【讨论】:

    • 我尝试了代码,但没有解决问题。我看到您使用日历 API 来修复日期而不是添加到毫秒。您是否还有其他具体的更改要提及。
    • 您假设EXPIRATIONTIME 以秒为单位设置,但根据您的代码,您正在使用System.currentTimeMillis() 创建日期,它使用毫秒而不是秒。因此,当您将EXPIRATIONTIME 添加到System.currentTimeMillis() 时,它被视为毫秒而不是秒。我试过你的代码,用你的代码生成的 JWT 有效期为 30 秒,根据你的代码是正确的。如果要设置为 30000,则必须将 EXPIRATIONTIME 设置为 30000000
    猜你喜欢
    • 2019-03-08
    • 2016-09-18
    • 2017-10-21
    • 2020-07-25
    • 1970-01-01
    • 2017-03-04
    • 2019-07-04
    • 1970-01-01
    • 2021-11-04
    相关资源
    最近更新 更多