JwtTokenUtil.java 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142
  1. package com.izouma.nineth.security;
  2. import com.izouma.nineth.domain.UserToken;
  3. import com.izouma.nineth.repo.UserTokenRepo;
  4. import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
  5. import io.jsonwebtoken.Claims;
  6. import io.jsonwebtoken.Clock;
  7. import io.jsonwebtoken.Jwts;
  8. import io.jsonwebtoken.SignatureAlgorithm;
  9. import io.jsonwebtoken.impl.DefaultClock;
  10. import org.springframework.security.core.userdetails.UserDetails;
  11. import org.springframework.stereotype.Component;
  12. import java.io.Serializable;
  13. import java.util.Date;
  14. import java.util.HashMap;
  15. import java.util.Map;
  16. import java.util.Optional;
  17. import java.util.function.Function;
  18. @Component
  19. public class JwtTokenUtil implements Serializable {
  20. private static final long serialVersionUID = -3301605591108950415L;
  21. static final String CLAIM_KEY_USERNAME = "sub";
  22. static final String CLAIM_KEY_CREATED = "iat";
  23. @SuppressFBWarnings(value = "SE_BAD_FIELD", justification = "It's okay here")
  24. private Clock clock = DefaultClock.INSTANCE;
  25. private JwtConfig jwtConfig;
  26. private final UserTokenRepo userTokenRepo;
  27. public JwtTokenUtil(JwtConfig jwtConfig, UserTokenRepo userTokenRepo) {
  28. this.jwtConfig = jwtConfig;
  29. this.userTokenRepo = userTokenRepo;
  30. }
  31. public String getUsernameFromToken(String token) {
  32. return getClaimFromToken(token, Claims::getSubject);
  33. }
  34. public Date getIssuedAtDateFromToken(String token) {
  35. return getClaimFromToken(token, Claims::getIssuedAt);
  36. }
  37. public Date getExpirationDateFromToken(String token) {
  38. return getClaimFromToken(token, Claims::getExpiration);
  39. }
  40. public <T> T getClaimFromToken(String token, Function<Claims, T> claimsResolver) {
  41. final Claims claims = getAllClaimsFromToken(token);
  42. return claimsResolver.apply(claims);
  43. }
  44. private Claims getAllClaimsFromToken(String token) {
  45. return Jwts.parser()
  46. .setSigningKey(jwtConfig.getSecret())
  47. .parseClaimsJws(token)
  48. .getBody();
  49. }
  50. private Boolean isTokenExpired(String token) {
  51. final Date expiration = getExpirationDateFromToken(token);
  52. Optional<UserToken> userToken = userTokenRepo.findById(getUsernameFromToken(token));
  53. if (!userToken.isPresent()) {
  54. return true;
  55. }
  56. if (!token.equals(userToken.get().getToken())) {
  57. return true;
  58. }
  59. return expiration.before(clock.now());
  60. }
  61. private Boolean isCreatedBeforeLastPasswordReset(Date created, Date lastPasswordReset) {
  62. return (lastPasswordReset != null && created.before(lastPasswordReset));
  63. }
  64. private Boolean ignoreTokenExpiration(String token) {
  65. // here you specify tokens, for that the expiration is ignored
  66. return false;
  67. }
  68. public String generateToken(UserDetails userDetails) {
  69. JwtUser jwtUser = (JwtUser) userDetails;
  70. Map<String, Object> claims = new HashMap<>();
  71. String token = doGenerateToken(claims, userDetails.getUsername());
  72. userTokenRepo.deleteById(jwtUser.getUser().getUsername());
  73. userTokenRepo.save(new UserToken(jwtUser.getUser().getUsername(), token));
  74. return token;
  75. }
  76. public String doGenerateToken(Map<String, Object> claims, String subject) {
  77. final Date createdDate = clock.now();
  78. final Date expirationDate = calculateExpirationDate(createdDate);
  79. return Jwts.builder()
  80. .setClaims(claims)
  81. .setSubject(subject)
  82. .setIssuedAt(createdDate)
  83. .setExpiration(expirationDate)
  84. .signWith(SignatureAlgorithm.HS512, jwtConfig.getSecret())
  85. .compact();
  86. }
  87. public Boolean canTokenBeRefreshed(String token, Date lastPasswordReset) {
  88. final Date created = getIssuedAtDateFromToken(token);
  89. return !isCreatedBeforeLastPasswordReset(created, lastPasswordReset)
  90. && (!isTokenExpired(token) || ignoreTokenExpiration(token));
  91. }
  92. public String refreshToken(String token) {
  93. final Date createdDate = clock.now();
  94. final Date expirationDate = calculateExpirationDate(createdDate);
  95. final Claims claims = getAllClaimsFromToken(token);
  96. claims.setIssuedAt(createdDate);
  97. claims.setExpiration(expirationDate);
  98. return Jwts.builder()
  99. .setClaims(claims)
  100. .signWith(SignatureAlgorithm.HS512, jwtConfig.getSecret())
  101. .compact();
  102. }
  103. public Boolean validateToken(String token, UserDetails userDetails) {
  104. JwtUser user = (JwtUser) userDetails;
  105. final String username = getUsernameFromToken(token);
  106. final Date created = getIssuedAtDateFromToken(token);
  107. //final Date expiration = getExpirationDateFromToken(token);
  108. return (
  109. username.equals(user.getUsername())
  110. && !isTokenExpired(token)
  111. && !isCreatedBeforeLastPasswordReset(created, user.getLastPasswordResetDate())
  112. );
  113. }
  114. private Date calculateExpirationDate(Date createdDate) {
  115. return new Date(createdDate.getTime() + jwtConfig.getExpiration() * 1000);
  116. }
  117. }