23.06.15
DEVOTEE를 활성화 시키면
지금 작성한 커뮤니티 글에 대해 1개의 댓글을 달아줍니다.
버튼을 누르면 글 수정 시 ChatGPT가 작성한 댓글이 수정됩니다.
| 컨텐츠 유형 | 제목 | 저장일 | 삭제 |
|---|
본인인증 로그인에 실패하였습니다.
회원이 아니시거나 본인인증 등록이
완료되지 않은 사용자입니다.
JWT(Jason Web Token) 은 별도의 세션을 유지할 필요없이 사용자의 Token 을 검증해서 인증을 해주기 때문에 속도가 빠르고 간단하게 시스템을 구현할 수 있습니다.
스프링 부트에 JWT 를 적용하는 방법을 간단한 코드 예제로 살펴 보도록 하겠습니다.
Spring Boot : 3.2.5
Java : 17(11이나 17이상도 상관 없습니다)
JWT Library : jjwt-api(0.12.5), jjwt-impl(0.12.5), jjwt-jackson(0.12.5)
(참고) Dependency 설정(gradle) : maven 에서 jjwt 검색해서 최신 버전을 적용해 주시면 됩니다
implementation group: 'io.jsonwebtoken', name: 'jjwt-api', version: '0.12.5'
runtimeOnly group: 'io.jsonwebtoken', name: 'jjwt-impl', version: '0.12.5'
runtimeOnly group: 'io.jsonwebtoken', name: 'jjwt-jackson', version: '0.12.5'JWT(발음에 주의 하셔야 합니다) 는 JSON 객체를 사용한 토큰기반의 인증방식을 제공합니다.
혹시 버스 토큰을 사용해 보신적 있으신가요? 저는 사용해 봤는데요..(아재인증 ㅜㅜ), 조그만 엽전 모양의 토큰을 버스 요금통에 집어 넣으면 버스를 탈 수 있었습니다.
이렇듯 토큰은 내가 뭔가를 사용하기 위해 필요한 수단이라고 보시면 됩니다.
[사용해 보신분?]
JWT 토큰의 구성은 대략 아래와 같습니다. 3부분으로 나뉘어 있는데, 우리가 토큰에 넣고 싶은 값(사용자 아이디, 이메일주소 등) 을 payload 에 작성하면 됩니다.
키 값은 문자열로 지정할 수 있는데, 이 값으로 HEADER+PAYLOAD를 해시로 암호화 하기 때문에 키는 잘 가지고 있어야 합니다.
[버스토큰, 아니 JWT 토큰의 구조]
http://jwt.io 사이트에 가보시면 sample 로 웹상에서 토큰을 만들어 볼 수도 있습니다.
이제 개념은 대략 이해했으니 실제 샘플 코드를 작성해 보겠습니다.
인터넷에 보통 있는 샘플 코드가 jjwt 이전 버전으로 작성되 있어서 최근 버전으로 변경했습니다.(0.11 버전대는 대부분 deprecate 됐습니다)
먼저 JWTService 클래스를 하나 작성합니다.
그리고 JWT 토큰을 만들어주는 create() 메서드와 토큰을 secret key 로 풀어서 검증해주는 validate() 메서드를 만들어 줍니다.
secret key 는 문자열로 지정했는데, 짧을 경우 오류가 발생할 수 있으니 충분히 길게 해져야 하지만 너무 길면 토큰 생성. 인증 프로세스에 로드가 걸리게 되니 적당히 작성해 줍니다.(256바이트)
암호화 알고리즘은 HS256을 사용 합니다.
Jwts 클래스는 static import 를 했습니다. 만약 static import 안하실 경우 Jwts.SIG.HS256 이런 식으로 Jwts 클래스를 붙여 주시면 됩니다.
(1) JWTService 클래스
package com.jwt.service;
import io.jsonwebtoken.ExpiredJwtException;
import io.jsonwebtoken.security.Keys;
import io.jsonwebtoken.security.SignatureException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import java.security.Key;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.Base64;
import java.util.Date;
import java.util.Map;
import static io.jsonwebtoken.Jwts.*;
@Service
@Slf4j
public class JWTService {
private static final String secretKey = "SpringSecurityKey_P@ssword_http://Spring.io";
private final Key key = Keys.hmacShaKeyFor(secretKey.getBytes());
public String create(
Map<String, Object> claims,
LocalDateTime expireAt
) {
var secretKeyBytes = Base64.getEncoder().encode(secretKey.getBytes());
//임의로 반든 암호키로 key를 설정해 줍니다(hmacShaKeyFor)
var key = Keys.hmacShaKeyFor(secretKeyBytes);
//token 의 Expire 시간을 변환해 줍니다
var _expireAt = Date.from(expireAt.atZone(ZoneId.systemDefault()).toInstant());
return builder()
.signWith(key, SIG.HS256)
.claims(claims)
.expiration(_expireAt)
.compact();
}
public void validate(String token) {
var secretKeyBytes = Base64.getEncoder().encode(secretKey.getBytes());
var key = Keys.hmacShaKeyFor(secretKeyBytes);
var parser = parser()
.verifyWith(key)
.build();
try {
var result = parser.parseSignedClaims(token);
result.getPayload().forEach((key1, value1) -> log.info("key : {}, value : {}", key1, value1));
} catch (Exception e) {
if (e instanceof SignatureException) {
throw new RuntimeException("JWT Token Invalid Exception");
} else if (e instanceof ExpiredJwtException) {
throw new RuntimeException("JWT Token Expired Exception");
} else {
throw new RuntimeException("JWT Exception");
}
}
}
}(2) 테스트할 테스트 코드를 만들어 줍니다. 저는 스프링부트의 기본 테스트 클래스를 사용했습니다.
package com.jwt;
import com.jwt.service.JWTService;
import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import java.time.LocalDateTime;
import java.util.HashMap;
@SpringBootTest
@Slf4j
class JwtApplicationTests {
@Autowired
JWTService jwtService;
@Test
void createToken() {
var claims = new HashMap<String, Object>();
claims.put("user_id", "devocean");
var expiredAt = LocalDateTime.now().plusMinutes(10);
var jwtToken = jwtService.create(claims, expiredAt);
log.info(jwtToken);
}
@Test
void validateToken() {
jwtService.validate(
"콘솔에 출력한 토큰 값을 넣어 줍니다");
}
}테스트 과정은 아래와 같습니다.
먼저, createToken 을 실행해 줍니다. 콘솔 창에 토큰이 출력 됩니다.
이 토큰값을 복사해서, validateToken 의 validate() 함수에 붙여넣기 해 줍니다. 테스트가 성공하고, 사용자 ID와 토큰 expire datetime(에포크 타임)을 콘솔에 출력합니다.
만약, 토큰 값을 임의로 변경하면 아래처럼 오류가 발생합니다.
테스트 코드에서는 현재 시간 + 10분 까지를 토큰의 만료 시간으로 지정했는데, create() 로 토큰을 생성하고 10분이 경과되면 오류가 발생합니다.
JWT 토큰을 사용함에 있어서 유의할 점은 만료 시간을 되도록 짧게 가져가야 키 관리의 보안에 문제가 없다는 점 입니다.
JWT를 사용하면 손쉽게 토큰을 발생하고 이 토큰을 사용해서 인증을 해 줄 수 있습니다.
Secret Key 관리에 유의해야 될 필요가 있으며 키가 유실될 경우를 대비한 Expire Date 의 적절한 설정이 필요 합니다.
Spring Security 의 필터를 사용해서 인증, 인가를 보다 쉽게 구현할 수 있습니다.
읽어 주셔서 감사합니다.
행복한 하루 되세요.
DEVOTEE를 활성화 시키면
지금 작성한 댓글에 AI가 댓글을 달아줍니다.