참고: Auth0 Java JWT
JWT를 사용하여 사용자 정의 매개변수와 타임스탬프로 토큰을 생성하고, 이를 통해 사용자 정보를 검증합니다. Auth0의 JWT 라이브러리는 자동으로 시간 만료 여부를 확인하며, 만료된 경우 TokenExpiredException 예외를 발생시킵니다.
1. 의존성 추가
<dependency> <groupId>com.auth0</groupId> <artifactId>java-jwt</artifactId> <version>3.10.3</version> </dependency>
2. 토큰 생성 및 검증 도구 클래스
import java.util.Date;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.exceptions.TokenExpiredException;
import com.auth0.jwt.interfaces.DecodedJWT;
@Component
public class JwtTokenService {
@Value("${jwt.issuer}")
private String issuer;
@Value("${jwt.audience}")
private String audience;
@Value("${jwt.expires_in}")
private int expiresIn;
private final String secretKey = "mySecretKey";
private final Algorithm algorithm = Algorithm.HMAC256(secretKey);
private Logger logger = LoggerFactory.getLogger(this.getClass());
public String createJwt(String userId) {
long currentTimeMillis = System.currentTimeMillis();
logger.info("토큰 생성 시간: " + new Date(currentTimeMillis));
logger.info("토큰 만료 시간: " + new Date(currentTimeMillis + expiresIn * 1000 * 60));
return JWT.create()
.withIssuer(issuer)
.withIssuedAt(new Date(currentTimeMillis))
.withExpiresAt(new Date(currentTimeMillis + expiresIn * 1000 * 60))
.withClaim("userId", userId)
.sign(algorithm);
}
public boolean validateJwt(String token) {
try {
if (token == null) {
logger.error("토큰이 없습니다.");
return false;
}
JWTVerifier verifier = JWT.require(algorithm).withIssuer(issuer).build();
DecodedJWT decodedJwt = verifier.verify(token);
String userId = decodedJwt.getClaim("userId").asString();
if (userId.isEmpty()) {
logger.error("사용자 ID가 잘못되었습니다.");
return false;
}
return true;
} catch (TokenExpiredException e) {
logger.error("토큰이 만료되었습니다.");
return false;
}
}
}
3. Spring 인터셉터에 토큰 검증 도구 추가
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
public class JwtInterceptor extends HandlerInterceptorAdapter {
private JwtTokenService jwtTokenService;
public JwtInterceptor(JwtTokenService jwtTokenService) {
this.jwtTokenService = jwtTokenService;
}
private Logger logger = LoggerFactory.getLogger(this.getClass());
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
boolean isValid = jwtTokenService.validateJwt(request.getHeader("Authorization"));
if (!isValid) {
response.setStatus(403);
logger.error("인증 실패");
}
return isValid;
}
}
4. 인터셉터 등록
import java.util.ArrayList;
import java.util.List;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class WebSecurityConfig implements WebMvcConfigurer {
private final JwtTokenService jwtTokenService;
public WebSecurityConfig(JwtTokenService jwtTokenService) {
this.jwtTokenService = jwtTokenService;
}
@Override
public void addInterceptors(InterceptorRegistry registry) {
List<String> excludedPaths = new ArrayList<>();
excludedPaths.add("/api/createToken");
registry.addInterceptor(new JwtInterceptor(jwtTokenService))
.addPathPatterns("/**")
.excludePathPatterns(excludedPaths);
}
}
5. 토큰 생성 API
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class TokenController {
@Autowired
private JwtTokenService jwtTokenService;
@PostMapping("/api/createToken")
public String generateToken(@RequestParam("userId") String userId) {
return jwtTokenService.createJwt(userId);
}
}
6. 다른 URL 접근 시 헤더에 토큰 필요
모든 API 요청에는 Authorization 헤더에 유효한 JWT 토큰이 포함되어야 합니다.