content: package com.flame.provider.zuul.utils;
  
  import com.flame.model.Authority;
  import com.flame.provider.zuul.utils.TimeProvider;
  import io.jsonwebtoken.Claims;
  import io.jsonwebtoken.Jwts;
  import io.jsonwebtoken.SignatureAlgorithm;
  import org.springframework.beans.factory.annotation.Autowired;
  import org.springframework.beans.factory.annotation.Value;
  import org.springframework.mobile.device.Device;
  import org.springframework.stereotype.Component;
  
  import java.io.Serializable;
  import java.util.Date;
  import java.util.HashMap;
  import java.util.Map;
  import java.util.function.Function;
  
  @Component
  public class JwtTokenUtil implements Serializable {
  
      private static final long serialVersionUID = -3301605591108950415L;
  
      static final String CLAIM_KEY_USERNAME = "sub";
      static final String CLAIM_KEY_AUDIENCE = "aud";
      static final String CLAIM_KEY_CREATED = "iat";
  
      static final String AUDIENCE_UNKNOWN = "unknown";
      static final String AUDIENCE_WEB = "web";
      static final String AUDIENCE_MOBILE = "mobile";
      static final String AUDIENCE_TABLET = "tablet";
  
      @Autowired
      private TimeProvider timeProvider;
  
      @Value("${jwt.secret}")
      private String secret;
  
      @Value("${jwt.expiration}")
      private Long expiration;
  
      public String getUsernameFromToken(String token) {
          return getClaimFromToken(token, Claims::getSubject);
      }
  
      public Date getIssuedAtDateFromToken(String token) {
          return getClaimFromToken(token, Claims::getIssuedAt);
      }
  
      public Date getExpirationDateFromToken(String token) {
          return getClaimFromToken(token, Claims::getExpiration);
      }
  
      public String getAudienceFromToken(String token) {
          return getClaimFromToken(token, Claims::getAudience);
      }
  
      public <T> T getClaimFromToken(String token, Function<Claims, T> claimsResolver) {
          final Claims claims = getAllClaimsFromToken(token);
          return claimsResolver.apply(claims);
      }
  
      private Claims getAllClaimsFromToken(String token) {
          return Jwts.parser()
                  .setSigningKey(secret)
                  .parseClaimsJws(token)
                  .getBody();
      }
  
      private Boolean isTokenExpired(String token) {
          final Date expiration = getExpirationDateFromToken(token);
          return expiration.before(timeProvider.now());
      }
  
      private Boolean isCreatedBeforeLastPasswordReset(Date created, Date lastPasswordReset) {
          return (lastPasswordReset != null && created.before(lastPasswordReset));
      }
  
      private String generateAudience(Device device) {
          String audience = AUDIENCE_UNKNOWN;
          if (device.isNormal()) {
              audience = AUDIENCE_WEB;
          } else if (device.isTablet()) {
              audience = AUDIENCE_TABLET;
          } else if (device.isMobile()) {
              audience = AUDIENCE_MOBILE;
          }
          return audience;
      }
  
      private Boolean ignoreTokenExpiration(String token) {
          String audience = getAudienceFromToken(token);
          return (AUDIENCE_TABLET.equals(audience) || AUDIENCE_MOBILE.equals(audience));
      }
  
      public String generateToken(Authority authority) {
          Map<String, Object> claims = new HashMap<>();
          return doGenerateToken(claims, authority.getAppKey());
      }
  
      private String doGenerateToken(Map<String, Object> claims, String subject) {
          final Date createdDate = timeProvider.now();
          final Date expirationDate = new Date(createdDate.getTime() + expiration * 1000);
  
  
          return Jwts.builder()
                  .setClaims(claims)
                  .setSubject(subject)
                  .setAudience("")
                  .setIssuedAt(createdDate)
                  .setExpiration(expirationDate)
                  .signWith(SignatureAlgorithm.HS512, secret)
                  .compact();
      }
  
      public Boolean canTokenBeRefreshed(String token, Date lastPasswordReset) {
          final Date created = getIssuedAtDateFromToken(token);
          return !isCreatedBeforeLastPasswordReset(created, lastPasswordReset)
                  && (!isTokenExpired(token) || ignoreTokenExpiration(token));
      }
  
      public String refreshToken(String token) {
          final Claims claims = getAllClaimsFromToken(token);
          claims.setIssuedAt(timeProvider.now());
          return doRefreshToken(claims);
      }
  
      public String doRefreshToken(Claims claims) {
          return Jwts.builder()
                  .setClaims(claims)
                  .signWith(SignatureAlgorithm.HS512, secret)
                  .compact();
      }
  
      public Boolean validateToken(String token, Authority authority) {
          final String username = getUsernameFromToken(token);
          final Date created = getIssuedAtDateFromToken(token);
          return (
                  username.equals(authority.getAppKey()));
      }
  }