오늘한일
- spring공부
- JWT란
JWT란
- JWT(Json Web Token)란 JSON 포맷을 이용하여 사용자에 대한 속성을 저장하는 Claim 기반의 Web Token 입니다. 즉, 토큰의 한 종류라고 생각하시면 됩니다. 일반적으로 쿠키 저장소를 사용하여 JWT를 저장합니다.
- JWT 장/단점
- 장점
- 동시 접속자가 많을 때 서버 측 부하 낮춤
- Client, Sever 가 다른 도메인을 사용할 때
- 예) 카카오 OAuth2 로그인 시 JWT Token 사용
- 단점
- 구현의 복잡도 증가
- JWT 에 담는 내용이 커질 수록 네트워크 비용 증가 (클라이언트 → 서버)
- 기 생성된 JWT 를 일부만 만료시킬 방법이 없음
- Secret key 유출 시 JWT 조작 가능
- 장점
JWT 생성
// 토큰 생성
public String createToken(String username, UserRoleEnum role) {
Date date = new Date();
return BEARER_PREFIX +
Jwts.builder()
.setSubject(username) // 사용자 식별자값(ID)
.claim(AUTHORIZATION_KEY, role) // 사용자 권한
.setExpiration(new Date(date.getTime() + TOKEN_TIME)) // 만료 시간
.setIssuedAt(date) // 발급일
.signWith(key, signatureAlgorithm) // 암호화 알고리즘
.compact();
}
JWT Cookie에 저장
// JWT Cookie 에 저장
public void addJwtToCookie(String token, HttpServletResponse res) {
try {
token = URLEncoder.encode(token, "utf-8").replaceAll("\\+", "%20"); // Cookie Value 에는 공백이 불가능해서 encoding 진행
Cookie cookie = new Cookie(AUTHORIZATION_HEADER, token); // Name-Value
cookie.setPath("/");
// Response 객체에 Cookie 추가
res.addCookie(cookie);
} catch (UnsupportedEncodingException e) {
logger.error(e.getMessage());
}
}
받아온 Cookie의 Value인 JWT 토큰 substring
// JWT 토큰 substring
public String substringToken(String tokenValue) {
if (StringUtils.hasText(tokenValue) && tokenValue.startsWith(BEARER_PREFIX)) {
return tokenValue.substring(7);
}
logger.error("Not Found Token");
throw new NullPointerException("Not Found Token");
}
.JWT 검증
// 토큰 검증
public boolean validateToken(String token) {
try {
Jwts.parserBuilder().setSigningKey(key).build().parseClaimsJws(token);
return true;
} catch (SecurityException | MalformedJwtException | SignatureException e) {
logger.error("Invalid JWT signature, 유효하지 않는 JWT 서명 입니다.");
} catch (ExpiredJwtException e) {
logger.error("Expired JWT token, 만료된 JWT token 입니다.");
} catch (UnsupportedJwtException e) {
logger.error("Unsupported JWT token, 지원되지 않는 JWT 토큰 입니다.");
} catch (IllegalArgumentException e) {
logger.error("JWT claims is empty, 잘못된 JWT 토큰 입니다.");
}
return false;
}
WT에서 사용자 정보 가져오기
// 토큰에서 사용자 정보 가져오기
public Claims getUserInfoFromToken(String token) {
return Jwts.parserBuilder().setSigningKey(key).build().parseClaimsJws(token).getBody();
}
JWT 테스트
@GetMapping("/create-jwt")
public String createJwt(HttpServletResponse res) {
// Jwt 생성
String token = jwtUtil.createToken("Robbie", UserRoleEnum.USER);
// Jwt 쿠키 저장
jwtUtil.addJwtToCookie(token, res);
return "createJwt : " + token;
}
@GetMapping("/get-jwt")
public String getJwt(@CookieValue(JwtUtil.AUTHORIZATION_HEADER) String tokenValue) {
// JWT 토큰 substring
String token = jwtUtil.substringToken(tokenValue);
// 토큰 검증
if(!jwtUtil.validateToken(token)){
throw new IllegalArgumentException("Token Error");
}
// 토큰에서 사용자 정보 가져오기
Claims info = jwtUtil.getUserInfoFromToken(token);
// 사용자 username
String username = info.getSubject();
System.out.println("username = " + username);
// 사용자 권한
String authority = (String) info.get(JwtUtil.AUTHORIZATION_KEY);
System.out.println("authority = " + authority);
return "getJwt : " + username + ", " + authority;
}
JWT 사용 시 주의 사항
서명이 되어 있는 JWT 토큰 서버에서만 유효성을 검증할 수 있지만 그 안에 저장된 데이터는 누구나 쉽게 열람이 가능합니다. 따라서 민감한 사용자 정보를 JWT 토큰에 그대로 저장하게 되면 큰 보안 문제로 이어질 수 있어서 각별한 주의가 필요하겠습니다.
가급적 JWT 토큰에는 사용자를 식별할 수 있는 아이디 정도만 저장하는 것이 좋으며 해당 사용자에 대한 추가 정보가 필요한 경우에는 서버에서 사용자 DB를 조회하는 것이 안전할 것입니다. 불가피한 이유로 JWT 토큰에 민감한 사용자 정보를 저장해야한다면 반드시 암호화를 하여 JWT 토큰을 디코딩한 후에도 알아볼 수 없게 해야할 것입니다.
느낀점
- JWT의 장점과 단점, 개념의 대해 좀더 알게되었다
'TIL' 카테고리의 다른 글
231110_TIL (0) | 2023.11.10 |
---|---|
231109_TIL (1) | 2023.11.09 |
231107_TIL (0) | 2023.11.07 |
231106_TIL (0) | 2023.11.06 |
231102_TIL (1) | 2023.11.02 |