package net.gepafin.tendermanagement.config.jwt; import io.jsonwebtoken.Claims; import io.jsonwebtoken.Jwts; import io.jsonwebtoken.SignatureAlgorithm; import io.jsonwebtoken.security.Keys; import jakarta.annotation.PostConstruct; import net.gepafin.tendermanagement.entities.UserEntity; import org.apache.commons.lang3.time.DateUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Value; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.core.Authentication; import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.authority.SimpleGrantedAuthority; import org.springframework.security.core.userdetails.User; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.stereotype.Component; import javax.crypto.SecretKey; import java.nio.charset.StandardCharsets; import java.util.*; import java.util.stream.Collectors; @Component public class TokenProvider { private final Logger log = LoggerFactory.getLogger(TokenProvider.class); @Value("${security.authentication.jwt.secret}") private String secretKey; @Value("${security.authentication.jwt.token-validity-in-seconds}") private long tokenValidityInSeconds; private SecretKey key; @PostConstruct public void init() { this.key = Keys.hmacShaKeyFor(secretKey.getBytes(StandardCharsets.UTF_8)); log.info("JWT Secret Key initialized."); } public String createToken(Authentication authentication, Boolean rememberMe, UserEntity user) { String authorities = authentication.getAuthorities().stream() .map(GrantedAuthority::getAuthority) .collect(Collectors.joining(",")); Long now; Date validity; if (Boolean.TRUE.equals(rememberMe)) { now = DateUtils.addMonths(new Date(), 2).getTime(); validity = new Date(now); log.info("Creating token with extended validity for 2 months."); } else { now = (new Date()).getTime(); validity = new Date(now + (this.tokenValidityInSeconds * 1000)); log.info("Creating token with standard validity of {} seconds.", this.tokenValidityInSeconds); } String payload = authentication.getName(); if(user != null) { payload += ":"+user.getId(); } String token = Jwts.builder() .setSubject(payload) .claim("auth", authorities) .signWith(key, SignatureAlgorithm.HS512) .setExpiration(validity) .compact(); log.debug("Generated token: {}", token); return token; } public Authentication getAuthentication(String token) { Claims claims = Jwts.parserBuilder() .setSigningKey(key) .build() .parseClaimsJws(token) .getBody(); UserDetails principal = new User(claims.getSubject(), "", Collections.emptyList()); log.info("Authenticated user: {}", claims.getSubject()); return new UsernamePasswordAuthenticationToken(principal, token, ClaimsToAuthorities(claims.get("auth"))); } private Collection ClaimsToAuthorities(Object authClaim) { Collection authorities = authClaim == null || ((String) authClaim).isEmpty() ? Collections.emptyList() : Arrays.stream(((String) authClaim).split(",")) .map(SimpleGrantedAuthority::new) .collect(Collectors.toList()); log.debug("Converted authorities from claims: {}", authorities); return authorities; } public boolean validateToken(String authToken) { try { Jwts.parserBuilder() .setSigningKey(key) .build() .parseClaimsJws(authToken); log.info("Token is valid."); return true; } catch (Exception e) { log.error("Token validation failed: {}", e.getMessage()); return false; } } }