Everyday Dev System

JWT version 0.11.5 본문

내배캠 주요 학습/Spring 숙련

JWT version 0.11.5

chaeyoung- 2023. 6. 19. 20:01
로그인 정보를 Server에 저장하지 않고 Client에 JWT로 암호화하여 저장한다.
또한 클라이언트에서 암호화하여 저장된 정보를 Server에 전송하여 JWT를 통해 인증 및 인가한다. 
(이때 Secret Key를 활용한다.)

**어떠한 기능들이 가진 메서드를 한 묶음 한 모듈 -> Util

 

 

build.gradle 에 의존성 추가

    // JWT
    compileOnly group: 'io.jsonwebtoken', name: 'jjwt-api', version: '0.11.5'
    runtimeOnly group: 'io.jsonwebtoken', name: 'jjwt-impl', version: '0.11.5'
    runtimeOnly group: 'io.jsonwebtoken', name: 'jjwt-jackson', version: '0.11.5'

 

application.properties 에 secret key 입력

jwt.secret.key=7Iqk7YyM66W07YOA7L2U65Sp7YG065+9U3ByaW5n6rCV7J2Y7Yqc7YSw7LWc7JuQ67mI7J6F64uI64ukLg==

 

 

<< JWT 생성 후 전달 방법 >>

JWT 토큰을 서버에서 Cookie를 만들어서 HttpServletRequest에 add해서 보내도 되고,
그냥 Response Header에 달아서 내보내는 방법도 있음.

 

 

@Component
public class JwtUtil {

    // Header KEY 값 (= cookie의 name 값)
    public static final String AUTHORIZATION_HEADER = "Authorization";
    
    // 사용자 권한 값의 KEY
    public static final String AUTHORIZATION_KEY = "auth";
    
    // Token 식별자
    public static final String BEARER_PREFIX = "Bearer ";
    
    // 토큰 만료시간
    private final long TOKEN_TIME = 60 * 60 * 1000L; // 60분

    @Value("${jwt.secret.key}") // Base64 Encode 한 SecretKey
    private String secretKey;
    
    private Key key;
    
    private final SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256;
    
    public static final Logger logger = LoggerFactory.getLogger("JWT 관련 로그");

    @PostConstruct
    public void init() {
        byte[] bytes = Base64.getDecoder().decode(secretKey);
        key = Keys.hmacShaKeyFor(bytes);
    }
    
    --중략--
}

private Key key는 Secret Key를 담을 Key 타입 객체이다.

암호화 혹은 복호화해서 검증할 때 사용할 멤버변수이다. 

 

 

@PostConstruct는 딱 한번만 받아오면 되는 값을 사용할 때마다 요청을 새로 호출하는 

실수를 방지하기 위해서 사용한다.

@PostConstruct가 기재된 메서드는 생성자가 호출되어 객체 생성이 된 다음에 해당 메서드가 실행이 된다.

    @PostConstruct
    public void init() {
        byte[] bytes = Base64.getDecoder().decode(secretKey);
        key = Keys.hmacShaKeyFor(bytes);
    }

 

jwt 토큰 생성하기

1. JWT 토큰 생성 

- Encoding하여 "Bearer 109skfjcojdsf~" 형식의 값을 반환한다.

    public String createToken(String username, UserRoleEnum role) {
        Date date = new Date();

        return BEARER_PREFIX +
                Jwts.builder()
                        .setSubject(username) // 사용자 식별자값(ID)
                        .claim(AUTHORIZATION_KEY, role) // 사용자 권한
                        .setExpiration(new Date(date.getTime() + TOKEN_TIME)) // 만료 시간
                        .setIssuedAt(date) // 발급일
                        .signWith(key, signatureAlgorithm) // 암호화 알고리즘
                        .compact();
    }

 

2. 생성된 JWT 토큰 Cookie에 저장

- 공백에 대해서만 Encoding한 후 cookie에 저장한다.

- 해당 쿠키를 HttpServletResponse에 add한다.

    public void addJwtToCookie(String token, HttpServletResponse res) {
    // 여기서 token은 "Bearer 109skfjcojdsf~" -> 공백 처리 필요
    
        try {
            token = URLEncoder.encode(token, "utf-8").replaceAll("\\+", "%20"); 
            // Cookie Value 에는 공백이 불가능해서 encoding 진행

            Cookie cookie = new Cookie(AUTHORIZATION_HEADER, token); // Name-Value
            cookie.setPath("/");

            res.addCookie(cookie);
            
        } catch (UnsupportedEncodingException e) {
            logger.error(e.getMessage());
        }
    }

 

결과 : 

토큰 생성

 

 

 

JWT 토큰 가져오기

1. JWT 토큰 자르기

- JWT 토큰에 있는 "Bearer "를 떼어내는 코드. -> 순수 토큰 코드만 남음.

    public String substringToken(String tokenValue) {
        if (StringUtils.hasText(tokenValue) && tokenValue.startsWith(BEARER_PREFIX)) {
            return tokenValue.substring(7);
        }
        logger.error("Not Found Token");
        throw new NullPointerException("Not Found Token");
    }

 

2. JWT 토큰 검증

Jwts.parserBuilder().setSigningKey(key).build().parseClaimsJws(token);

JWT 토큰을 검증하는 코드

    public boolean validateToken(String token) {
        try {
            Jwts.parserBuilder().setSigningKey(key).build().parseClaimsJws(token);
            return true;
        } catch (SecurityException | MalformedJwtException | SignatureException e) {
            logger.error("Invalid JWT signature, 유효하지 않는 JWT 서명 입니다.");
        } catch (ExpiredJwtException e) {
            logger.error("Expired JWT token, 만료된 JWT token 입니다.");
        } catch (UnsupportedJwtException e) {
            logger.error("Unsupported JWT token, 지원되지 않는 JWT 토큰 입니다.");
        } catch (IllegalArgumentException e) {
            logger.error("JWT claims is empty, 잘못된 JWT 토큰 입니다.");
        }
        return false;
    }

 

3.  JWT에서 사용자 정보 가져오기

    public Claims getUserInfoFromToken(String token) {
        return Jwts.parserBuilder().setSigningKey(key).build().parseClaimsJws(token).getBody();
    }

 

결과 : 

토큰 가져오기

'내배캠 주요 학습 > Spring 숙련' 카테고리의 다른 글

Spring 에서 Filter란?  (0) 2023.06.20
로그인 구현하기  (0) 2023.06.19
회원가입 구현하기  (0) 2023.06.19
인증 - 쿠키와 세션  (1) 2023.06.19
같은 타입의 Bean 객체 활용하기  (0) 2023.06.19