본문 바로가기
Spring

Spring Boot에서 JWT 사용하기

by 박주봉 2020. 5. 18.

1. JWT 소개

JWT (JSON Web Token)는 개방형 표준 ( RFC 7519 )으로 당사자간에 정보를 JSON 객체로 안전하게 전송하기위한 간결하고 독립적 인 방법을 정의합니다. 이 정보는 디지털 서명되어 있으므로 확인하고 신뢰할 수 있습니다. JWT는 비밀 ( HMAC 알고리즘 사용) 또는 RSA 또는 ECDSA를 사용하는 공개 / 개인 키 쌍을 사용하여 서명 할 수 있습니다 .

출처 : https://jwt.io/introduction/

간단하게 말해 JSON 객체를 주고받을 때 토큰을 확인하여 맞을 경우 데이터를 넘겨준다고 생각하면 될 것 같습니다. 

ex) 로그인 요청 (클라이언트) -> 로그인 확인 후 토큰 발급 (서버) -> 발급 된 토큰으로 Rest API 요청 (클라이언트)

JWT 에 대한 자세한 정보는 jwt.io 에서 확인 하실 수 있습니다.

2. JWT 시작하기

jwt.io 에서 Java 에서 가장 Star 가 많은 jsonwebtoken 을 선택해서 구현해봤습니다.

gradle dependencies 추가

dependencies {
	compile('org.springframework.boot:spring-boot-starter-web')
	compile('io.jsonwebtoken:jjwt-api:0.11.1')
    runtime('io.jsonwebtoken:jjwt-impl:0.11.1', 'io.jsonwebtoken:jjwt-jackson:0.11.1')

    testCompile('org.springframework.boot:spring-boot-starter-test')
}

토큰 클래스 (TokenProvider)

package com.bonjour.jwt.service;

import io.jsonwebtoken.JwtException;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import io.jsonwebtoken.security.Keys;
import org.springframework.stereotype.Service;

import javax.crypto.SecretKey;
import java.util.Calendar;
import java.util.Date;

@Service
public class TokenProvider {

    private SecretKey key = Keys.secretKeyFor(SignatureAlgorithm.HS256); // 토큰 암호화키
    private int tokenExpirationMsec = 1800000;  // 만료시간 30분

    public String createToken() {

        // setExpiration 매개변수가 Date로 되어있어 LocalDateTime를 사용하지 못함
        Date now = new Date();
        Calendar calendar = Calendar.getInstance();
        calendar.add(Calendar.MILLISECOND, tokenExpirationMsec);
        Date expiryDate =  calendar.getTime();

        return Jwts.builder()
                .setSubject("Bonjour Park")
                .setIssuedAt(now)
                .setExpiration(expiryDate)
                .signWith(key, SignatureAlgorithm.HS256)
                .compact();
    }

    public boolean validateToken(String authToken) throws JwtException{

        try {
            Jwts.parserBuilder()
                    .setSigningKey(key)
                    .build()
                    .parseClaimsJws(authToken);
            return true;
        } catch (JwtException e) {
            e.printStackTrace();
        }
        return false;
    }
}

3. JWT 토큰 발급 테스트

package com.bonjour.jwt.service;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

@RunWith(SpringRunner.class)
@SpringBootTest
public class TokenProviderTest{
    @Autowired
    TokenProvider tokenProvider;

    @Test
    public void 토큰_생성하기() {
        String token = tokenProvider.createToken();
        System.out.println(">>>>>>>>>>>>>> token = " + token);
    }

    @Test
    public void 토큰_검증하기() {
        String token = tokenProvider.createToken();
        System.out.println(token);
        tokenProvider.validateToken(token);
    }
}

 

토큰 생성 결과 

위 그림과 같이 테스트는 성공적으로 통과되었으며, 테스트 결과는 아래처럼 토큰이 출력되었습니다.

eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJCb25qb3VyIFBhcmsiLCJpYXQiOjE1ODk3OTY4MjgsImV4cCI6MTU4OTc5ODYyOH0.6xWO0himxrmkaXdqIorkTcgV6owZ5QomoNqDjxhsfus

발급 된 토큰 정보를 jwt.io 에서 확인해 보겠습니다.

코드에 픽스되어 있던 값들이 정상적으로 확인됩니다.

이제 토큰 검증을 위한 테스트를 실행하겠습니다.

테스트는 성공적으로 통과했습니다.

마지막으로 토큰 만료시간의 값을 0으로 바꾸어 테스트를 해보겠습니다.

 

테스트 결과 토큰 만료시간이 지났다는 메세지가 출력됩니다.

전체소스 보기

4. 결론

JWT 토큰을 사용하는 가치는 충분히 있다고 생각이 됩니다.

  • DB Access 가 최소화 되어 트래픽에 대한 부담이 낮음
  • Rest API 의 보안 문제를 해결해 줄 수 있음
  • 선택적인 권한 부여가 쉽게 이루어 질 수 있음

물론 토큰 탈취에 대한 대비, 토큰인증 만료시간에 따른 Refresh Token 의 구현, 로그아웃 시 blacklist 에 대한 비용이 발생합니다. 하지만 일반 웹 로그인, 권한확인에 비해 훨씬 간편하고 확장성이 높다고 생각됩니다.

'Spring' 카테고리의 다른 글

Spring WebFlux  (0) 2021.07.23
Spring Boot 에서 H2 innodb 오류 해결  (1) 2020.05.22

댓글