728x90
일단 build.gradle 에 의존성을 추가하자
참고로 jdk 17 을 사용 했다
1 2 3 4 5 | // JWT // https://github.com/jwtk/jjwt implementation 'io.jsonwebtoken:jjwt-api:0.12.5' runtimeOnly 'io.jsonwebtoken:jjwt-impl:0.12.5' runtimeOnly 'io.jsonwebtoken:jjwt-jackson:0.12.5' | cs |
다음은 JwtTest 파일 이다
1 2 3 4 5 6 7 8 9 10 | class JwtTest { String secretKey = "66650E3CBCF3E6E1DB2F5D3CDCAB8B9AED0198DE0C060064E270C2199329F1B85191162AA80AD0C4EC79A38E2E475186E9E7F0BBAD38D05A9C732F5B5B5E7B2C"; byte[] secretKeyBytes = secretKey.getBytes(StandardCharsets.UTF_8); SecretKey key = Keys.hmacShaKeyFor(secretKeyBytes);// 512 비트이면 SHA-512 동작한다 ... } | cs |
hmacShaKeyFor 메서드를 보면 512 비트가 넘어가면 sha-512 해시함수를 사용한다
그러기 때문에 시크릿키가 512 비트가 넘어가는 문자열을 준비했다
토큰 생성 테스트 코드이다 보면 쉽다
claim 부분에 내가 토큰에 넣을 데이터를 넣어주는데
테스트여서 패스워드 칼럼을 넣었지만, 실무에서는 개인정보는 넣지말자
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 | @Test void 토큰_생성() { SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:sss"); // 현재 순간 Instant instant = Instant.now(); // 생성일 Date createDate = Date.from(instant); String startDateText = sdf.format(createDate); // 만료일 Date endDate = Date.from(instant.plus(30, ChronoUnit.SECONDS)); // 30초 후 String endDateText = sdf.format(endDate); System.out.println("startDateText = " + startDateText); System.out.println("endDateText = " + endDateText); String token = Jwts.builder() .subject("토큰제목") .issuedAt(createDate) .expiration(endDate) .claim("userId", "1111") .claim("password", "2222") .signWith(key) // 서명 .compact(); System.out.println("token"); System.out.println(token); } | cs |
결과는 다음과 같다
1 2 3 4 5 | startDateText = 2024-06-03 00:00:049 endDateText = 2024-06-03 00:01:019 token eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiLthqDtgbDsoJzrqqkiLCJpYXQiOjE3MTczNDA0NDksImV4cCI6MTcxNzM0MDQ3OSwidXNlcklkIjoiMTExMSIsInBhc3N3b3JkIjoiMjIyMiJ9.EFqJ9KI2rVVqrcpxgeFqzoGv_TVOUFgKWBcZ-LaYuk-a_Z6HwL05e4t07V_b_VB-vrWJxw_9WrXlHN5k5VPFaw | cs |
이제 검증을 해보자
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 | @Test void 토큰_검증() throws Exception { JwtParser jwtParser = Jwts.parser() .verifyWith(key) .build(); try { // 파라미터로 토큰 문자열을 넣어준다 // 토큰이 만료되면 ExpiredJwtException 예외가 터진다 Jwt<?, ?> jwt = jwtParser.parse("eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiLthqDtgbDsoJzrqqkiLCJpYXQiOjE3MTcyNDc3ODQsImV4cCI6MTcxNzI0NzgxNCwidXNlcklkIjoiMTExMSIsInBhc3N3b3JkIjoiMjIyMiJ9.mNz4hwmszUMd1XNGX9_7UK1ND5h2e5cIsJpXnln2Tyb4SZ9diHRtUzJyKw_xstd4vxGIcwBSwt4mWxu9qxDJAQ"); System.out.println("jwt = " + jwt); Header header = jwt.getHeader(); System.out.println("header = " + header); String alg = (String) header.get("alg"); System.out.println("alg = " + alg); Claims claims = (Claims) jwt.getPayload(); System.out.println("claims = " + claims); String userId = (String) claims.get("userId"); String password = (String) claims.get("password"); System.out.println("userId = " + userId); System.out.println("password = " + password); } catch(Exception e) { // ExpiredJwtException e.printStackTrace(); } } | cs |
토큰이 만료되었다면 다음과 같은 ExpiredJwtException 예외가 터진다
토큰이 유효하면 다음과 같이 출력이 잘된다
1 2 3 4 5 6 7 | jwt = header={alg=HS512},payload={sub=토큰제목, iat=1717248046, exp=1717248076, userId=1111, password=2222},signature=OSmw7n8OF_crspRpAWhKJ_jEvWrUfsCVxCIcx_supn4ggHDewyJN0132V6vg__4UWMM0hcbBthXTZKExQZ5FRA header = {alg=HS512} alg = HS512 claims = {sub=토큰제목, iat=1717248046, exp=1717248076, userId=1111, password=2222} userId = 1111 password = 2222 | cs |
다음은 토큰을 그냥 Base64 로 디코딩 해서 읽어버리자
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | @Test public void base64_decoding() throws Exception { ObjectMapper mapper = new ObjectMapper(); String token = "eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiLthqDtgbDsoJzrqqkiLCJpYXQiOjE3MTcyNDgwNDYsImV4cCI6MTcxNzI0ODA3NiwidXNlcklkIjoiMTExMSIsInBhc3N3b3JkIjoiMjIyMiJ9.OSmw7n8OF_crspRpAWhKJ_jEvWrUfsCVxCIcx_supn4ggHDewyJN0132V6vg__4UWMM0hcbBthXTZKExQZ5FRA"; String[] chunks = token.split("\\."); Base64.Decoder decode = Base64.getUrlDecoder(); byte[] decodeByteArr = decode.decode(chunks[1]); // 0 : 헤더, 1 : 페이로드, 2 : 시그니처 String jsonText = new String(decodeByteArr); Map<String,String> dataMap = mapper.readValue(jsonText, Map.class); System.out.println("dataMap = " + dataMap); } | cs |
출력은 다음과 같다
1 | dataMap = {sub=토큰제목, iat=1717248046, exp=1717248076, userId=1111, password=2222} | cs |
시큐리티에 녹이는건 너무 분량이많아서 생략한다...
728x90
'개발 > spring-security' 카테고리의 다른 글
rememberMe 에 대하여 (4) | 2024.10.26 |
---|---|
HttpSecurity, WebSecurity 생성 과정 디버깅 해보기 (0) | 2024.08.07 |
spring security 와 jwt 주저리 (0) | 2024.06.01 |
JWT 토큰 (0) | 2024.06.01 |
커스텀 Filter 에 AuthenticationManager 공유하기 (0) | 2024.05.23 |