- K6로 토큰 인증 절차가 필요한 API 테스트 하기2025년 02월 24일 20시 39분 36초에 업로드 된 글입니다.작성자: do_hyuk
부하 및 성능 테스트 도구인 k6를 사용해서 api 테스트를 진행하려던 중
JWT access token을 필요로 하는 api를 테스트하기 위해서 k6에서 어떤 식으로 토큰을 처리해야할 지 알아보자.
일단 기존 코드에서 access token을 어떻게 생성하는지 부터 알아보았다.
JwtProvider.class
private Key key; @Value("${jwt.accessTokenExpireTime}") private long accessTokenExpireTime; @Value("${jwt.refreshTokenExpireTime}") private long refreshTokenExpireTime; @Value("${jwt.secret}") private String secretKey; ... @PostConstruct public void init() { byte[] bytes = Base64.getDecoder() .decode(secretKey);// Base64로 인코딩된 값을 시크릿키 변수에 저장한 값을 디코딩하여 바이트 배열로 변환 //* Base64 (64진법) : 바이너리(2진) 데이터를 문자 코드에 영향을 받지 않는 공통 ASCII문자로 표현하기 위해 만들어진 인코딩 key = Keys.hmacShaKeyFor( bytes);//디코팅된 바이트 배열을 기반으로 HMAC-SHA 알고르즘을 사용해서 Key객체로 반환 , 이를 key 변수에 대입 } // 액세스 토큰 발급 public JwtDto generateToken(Authentication authentication) { long now = (new Date()).getTime(); Date accessTokenExpiration = new Date(now + accessTokenExpireTime); // Authorities를 Claim에 넣을 수 있도록 String으로 변경 (authority1,authority2,..) String authorities = authentication.getAuthorities().stream() .map(GrantedAuthority::getAuthority) .collect(Collectors.joining(",")); String accessToken = Jwts.builder() .subject(authentication.getName()) .claim("auth", authorities) .expiration(accessTokenExpiration) .signWith(key) .compact(); String refreshToken = Jwts.builder() .expiration(new Date(now + refreshTokenExpireTime)) .signWith(key) .compact(); return JwtDto.builder() .accessToken(BEARER_PREFIX + accessToken) .refreshToken(refreshToken) .build(); }
간단하게 설명하자면 JWT 토큰을 만들기 위해 secrete 키를 base64로 디코딩한 key와 회원 정보, 권한, 만료기간 데이터들을 Jwts.builder()로 생성해준다.
K6
위에 JwtProvider 클래스를 통해 토큰을 생성하기 위해 필요한 데이터로는 secrete key, 회원 이름, 권한, 만료기간이 있음을 확인했다.
그럼 이제 k6에서 토큰을 직접 생성해보겠다.
테스트로 사용한 API는 access token에서 payload의 sub 값을 로그로 호출하는 테스트 API를 사용하였다.
jwt_test.js
import http from 'k6/http'; import { check, sleep } from 'k6'; import {encode} from "./util.js"; export const options = { vus: 1, duration: '1s', }; export default function() { const data = { "sub" : "abc@naver.com", "auth" : "손님,회원", "exp" : Date.now() + 1800000 } const acc = encode(data, SECRETE_KEY); console.log(acc); const response = http.get("http://host.docker.internal:8080/v1/api/auth/test", { headers: { 'Content-Type': 'application/json', 'Authorization' : `Bearer ${acc}` } }); check(response, { "is status 200" :(r) => r.status === 200 }) sleep(1); }
지금은 토큰이 잘 생성되는지 확인하기 위해 테스터 한명의 정보만을 사용했다.
util.js
// util.js import encoding from 'k6/encoding'; import crypto from 'k6/crypto'; const sign = (data, alg, secret) => { const hasher = crypto.createHMAC(alg, decodedSecret); hasher.update(data); return hasher.digest("base64rawurl"); }; export const encode = (payloadData, secret) =>{ const headerData = { "alg": "HS384", } const header = encoding.b64encode(JSON.stringify(headerData), "rawurl"); const payload = encoding.b64encode(JSON.stringify(payloadData), "rawurl"); const sig = sign(header+"."+payload, "sha384", secret); return [header, payload, sig].join("."); }
암호화 알고리즘으로 HS384 : sha-384를 사용한 이유는 기존 코드에서 어떤 알고리즘을 사용했는지 표기가 되어있지 않아서 기존에 사용하던 access token을 Decoder 사이트에서 디코딩 해본 뒤 확인하여 적용한 것이다.
테스트를 실행한 결과가 잘 나오는 것을 확인할 수 있다.
핵심 지표 요약 이 결과는 초기 테스트 환경 검증에 적합하지만, 실제 서비스 환경에서는 VUs 증가와 장시간 테스트를 추가해야 한다.
// 예시: 10 VUs로 5분간 테스트 const vu = new VUCount(10, 5 * 60);
또한 이번에는 로컬 환경에서 테스트로 진행하였지만 이 후에는 배포 서버와 같은 환경인 개발 서버에서 성능테스트를 진행하겠다.
'포트폴리오 > AutoReview' 카테고리의 다른 글
배포된 데이터베이스의 스키마를 변경해보자(1) (0) 2025.03.11 연관관계 설정은 필수일까? (0) 2025.03.07 [feature] 댓글 공개 여부 기능 추가(1) (0) 2025.02.21 [feature] 댓글 기능 추가 (0) 2025.02.19 트랜잭션(Transaction) 분리하기 (0) 2025.02.11 댓글