첫번째의 JWT는 JWT에 대한 간단한 설명을 정리했고 2번째는 Spring Boot 환경에서 JWT를 직접 생성해보고자 한다.
사실 JWT 생성은
https://jwt.io/
해당 홈페이지에서 직접 PayLoad값을 넣어가며 생성할 수 있다.
하지만 실무 백엔드에서 JWT를 활용할 수 있는 간단한 JWT 생성코드를 정리해 보고자한다. 생성에는 jjwt 플러그인을 활용하였다.
1. build.gradle 설정에 io.jsonwebtoken:jjwt 플러그인을 추가한다.
implementation 'io.jsonwebtoken:jjwt-api:0.11.2'
implementation 'io.jsonwebtoken:jjwt-impl:0.11.2'
implementation 'io.jsonwebtoken:jjwt-jackson:0.11.2'
2. JWT 코드 작성하기
우선 JWT 생성은 간단하게 4가지 단계가 있다.
- Header 값 생성
- PayLoad
- Signature(서명)
- 생성
1,2번의 값들은 모두 Map형태의 Key, Value 값으로 정의한다.
2-1. Header값 생성
Map<String, Object> headers = new HashMap<>(); headers.put("typ", "JWT"); // 타입은 JWT headers.put("alg", "HS256"); // 서명 알고리즘 유형
2-2. PayLoad값 생성
Map<String, Object> payloads = new HashMap<>();
payloads.put("KEY", "HelloWorld"); payloads.put("NickName","Erjuer");
payloads.put("Age","29"); payloads.put("TempAuth","Y");
2-3. Signature(서명)
JWT 관련하여 구글링을 해보니 서명 부분에서 .signWith(io.jsonwebtoken.SignatureAlgorithm, java.lang.String)를 활용하는 예제들을 많이 봤다.
하지만 signWith(io.jsonwebtoken.SignatureAlgorithm, java.lang.String)' is deprecated 되어 String값을 넣는 것이 아닌 Key값을 생성하고 서명을 진행해야 한다.
// String str = "MyNickNameisErjuerAndNameisMinsu" 값을 byte 형변환
Key key = Keys.hmacShaKeyFor("MyNickNameisErjuerAndNameisMinsu".getBytes(StandardCharsets.UTF_8));
String 값으로 Utf8로 인코딩후 Byte로 형변환 할 때 다음과 같은 Exception이 터질 수도 있다.
io.jsonwebtoken.security.WeakKeyException: The specified key byte array is 96 bits which is not secure enough for any JWT HMAC-HA algorithm.
The JWT JWA Specification (RFC 7518, Section 3.2) states that keys used with HMAC-SHA algorithms MUST have a size >= 256 bits (the key size must be greater than or equal to the hash output size).
Consider using the io.jsonwebtoken.security.Keys
#secretKeyFor(SignatureAlgorithm) method to create a key guaranteed to be secure enough for your preferred HMAC-SHA algorithm.
See https://tools.ietf.org/html/rfc7518#section-3.2 for more information.
: 요약하자면 256bit보다 커야 한다. 영어 한단어당 8bit 이므로 32글자 이상이어야 한다는 뜻이다.
여기서 궁금한 것 하나 한글은 한글자당 16bit인데 16글자이면 생성이 될까?
'제블로그에오신여러분을환영합니다' => 생성된다.
public static SecretKey hmacShaKeyFor(byte[] bytes) throws WeakKeyException {
if (bytes == null) {
throw new InvalidKeyException("SecretKey byte array cannot be null.");
}
int bitLength = bytes.length * 8;
for (SignatureAlgorithm alg : PREFERRED_HMAC_ALGS) {
if (bitLength >= alg.getMinKeyLength()) {
return new SecretKeySpec(bytes, alg.getJcaName());
}
}
String msg = "The specified key byte array is " + bitLength + " bits which " +
"is not secure enough for any JWT HMAC-SHA algorithm.
The JWT " + " JWA Specification (RFC 7518, Section 3.2)
states that keys used with HMAC -SHA algorithms MUST have a "
+ "size >= 256 bits (the key size must be greater than or equal to the hash "
+ "output size). Consider using the " + Keys.class.getName()
+ "#secretKeyFor(SignatureAlgorithm) method "
+ "to create a key guaranteed to be secure enough for your preferred HMAC-SHA algorithm. See " + "https://tools.ietf.org/html/rfc7518#section-3.2 for more information.";
throw new WeakKeyException(msg);
}
2-4. 생성
토큰 만료 시간을 설정해주고 Header값과 payLoad 그리고 서명을 진행한다.
// 토큰 만료 시간 Long expiredTime = 1000 * 60L * 60L * 1L;
// 토큰 유효 시간 (밀리 세컨드 단위)
Date expireDate = new Date();
expireDate.setTime(expireDate.getTime() + expiredTime);
// 토큰 Builder String jwt = Jwts.builder() .setHeader(headers)
// Headers 설정 .setClaims(payloads)
// Claims 설정 .setSubject("Test")
// 토큰 용도 .setExpiration(expireDate)
// 토큰 만료 시간 설정
.signWith(key, SignatureAlgorithm.HS256) .compact(); // 토큰 생성
JWT : eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJOaWNrTmFtZSI6IkVyanVlciIsIlRlbXBBdXRoIjoiWSIsIktFWSI6IkhlbGxvV29ybGQiLCJBZ2UiOiIyOSIsInN1YiI6IlRlc3QiLCJleHAiOjE2MzUxNzg4NTF9.ad539kso90a8Hm5_Iv3xiXgrLJ4Qjo52sR7pXGr4Hr0
JWT값이 생성되는 것을 확인할 수 있다.
JWT값을 jwt.io 페이지에서 확인해보면
PayLoad값에 내가 Map 형태로 저장했던 값들을 확인할 수 있다.
해당 값을 Fronted와 Backend HTTP 통신에 Header값으로 넣고 설정하여 간단한 인증 절차를 진행 할 수 있다.
다음 정리글은 받은 값을 Header와 PayLoad로 추출해보는 작업을 진행해보려 한다.
<JWT 생성 예시 코드>
@SpringBootTest
public class JwtTest {
@Test
public void createToken() {
//Header 부분 설정
Map<String, Object> headers = new HashMap<>();
headers.put("typ", "JWT");
headers.put("alg", "HS256");
//payload 부분 설정
Map<String, Object> payloads = new HashMap<>();
payloads.put("KEY", "HelloWorld");
payloads.put("NickName","Erjuer");
payloads.put("Age","29");
payloads.put("TempAuth","Y");
Long expiredTime = 1000 * 60L * 60L * 1L; // 토큰 유효 시간 (2시간)
Date date = new Date(); // 토큰 만료 시간
date.setTime(date.getTime() + expiredTime);
Key key = Keys.hmacShaKeyFor("MyNickNameisErjuerAndNameisMinsu".getBytes(StandardCharsets.UTF_8));
// 토큰 Builder
String jwt = Jwts.builder()
.setHeader(headers) // Headers 설정
.setClaims(payloads) // Claims 설정
.setSubject("Test") // 토큰 용도
.setExpiration(date) // 토큰 만료 시간 설정
.signWith(key, SignatureAlgorithm.HS256)
.compact(); // 토큰 생성
System.out.println(">> jwt : " + jwt);
}
}
끝.
'개발 지식 > Spring Framework' 카테고리의 다른 글
[Test] Controller Test mockMvc 활용 (0) | 2022.04.26 |
---|---|
[thymeleaf] 기본 기능 정리 - 01 (0) | 2021.12.16 |
[Redis Session] Spring Boot에서 Redis Session 활용하기 - 04 (0) | 2021.09.26 |
[Redis Session] Spring Boot에서 Redis Session 활용하기 - 03 (0) | 2021.09.24 |
[Redis Session] Spring Boot에서 Redis Session 활용하기 - 02 (0) | 2021.09.23 |
댓글