Spring Boot와 JWT를 활용한 인증 시스템 구현
1. Maven 의존성 추가
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.9.1</version>
</dependency>
<dependency>
<groupId>com.auth0</groupId>
<artifactId>java-jwt</artifactId>
<version>3.4.0</version>
</dependency>
2. JWT 유틸리티 클래스 (TokenUtil)
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.JwtBuilder;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.apache.commons.codec.binary.Base64;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
public class TokenUtil {
private static final long TOKEN_EXPIRE_TIME = 30 * 24 * 60 * 60;
private static final String JWT_SECERT = "MDk4ZjZiY2Q0NjIxZDM3M2NhZGU0ZTgzMjYyN2I0ZjY=";
public static final String TOKEN_ID = "tokenId";
public static String createToken(Map claims, Long time) {
SignatureAlgorithm algorithm = SignatureAlgorithm.HS256;
Date now = new Date(System.currentTimeMillis());
SecretKey key = generateKey();
long nowMillis = System.currentTimeMillis();
JwtBuilder builder = Jwts.builder()
.setClaims(claims)
.setId(TOKEN_ID)
.setIssuedAt(now)
.signWith(algorithm, key);
if (time >= 0) {
long expMillis = nowMillis + time;
Date exp = new Date(expMillis);
builder.setExpiration(exp);
}
return builder.compact();
}
public static Claims verifyToken(String token) {
SecretKey key = generateKey();
Claims claims;
try {
claims = Jwts.parser()
.setSigningKey(key)
.parseClaimsJws(token)
.getBody();
} catch (Exception e) {
claims = null;
}
return claims;
}
private static SecretKey generateKey() {
String stringKey = JWT_SECERT;
byte[] encodedKey = Base64.decodeBase64(stringKey);
SecretKey key = new SecretKeySpec(encodedKey, 0, encodedKey.length, "AES");
return key;
}
public static String generateToken(String openId, Integer userId) {
Map map = new HashMap<>();
map.put("userId", userId);
map.put("openId", openId);
return createToken(map, TOKEN_EXPIRE_TIME);
}
}
3. JWT 필터 (TokenFilter)
import com.llh.chat.util.TokenUtil;
import io.jsonwebtoken.Claims;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
public class TokenFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain)
throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) servletRequest;
HttpServletResponse response = (HttpServletResponse) servletResponse;
String token = request.getHeader("authorization");
Claims claims = TokenUtil.verifyToken(token);
if (claims == null) {
response.getWriter().write("토큰이 유효하지 않습니다.");
} else {
filterChain.doFilter(request, response);
}
}
@Override
public void destroy() {
}
}
4. 필터 빈 등록 설정 (BeanRegisterConfig)
import com.llh.chat.filter.TokenFilter;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class BeanRegisterConfig {
@Bean
public FilterRegistrationBean createFilterBean() {
FilterRegistrationBean registration = new FilterRegistrationBean();
registration.setFilter(new TokenFilter());
registration.addUrlPatterns("/user/hello");
return registration;
}
}
5. Controller 예제
@RestController
public class LoginController {
@RequestMapping("/user/login")
public String login() {
String jwtToken = TokenUtil.generateToken("123", 456);
return jwtToken;
}
@RequestMapping("user/hello")
public String user() {
return "hello JWT";
}
}
6. Postman을 활용한 테스트 방법
다음 토큰을 Postman의 Authorization 헤더에 추가하여 요청합니다:
eyJhbGciOiJIUzI1NiJ9.eyJvcGVuSWQiOiIxMjMiLCJleHAiOjE2MDEwMjA0NTcsInVzZXJJZCI6NDU2LCJpYXQiOjE2MDEwMTc4NjUsImp0aSI6InRva2VuSWQifQ.ic0z-Iel2Mk4c0xluuk6AijvxgzZZqAktKNMin6N0SU