스프링 부트에서 JWT(Json Web Token) 구현

egov

라이브러리 설정

우선 나의 환경은 gradle을 이용하였고 2.0.3 RELEASE 버전의 스프링부트를 이용하였다.

우선 그레들에서 dependency에 다음과 같이 추가한다.

    compile('org.springframework.boot:spring-boot-starter-data-jpa')
    compile 'io.jsonwebtoken:jjwt:0.9.0'
    compile('org.springframework.boot:spring-boot-starter-web')
    testCompile('org.springframework.boot:spring-boot-starter-test')


    단순 구현만 하기 위해 디비설정은 하지 않았다.
    이 포스팅에서는 라이브러리를 jjwt를 이용하여 jwt 생성 및 디코딩만 할 것이다.

컨트롤러

    내 컨트롤러는 화면단과 클라이언트 단을 분리하기 위해 @RestController 어노테이션을 사용하였고,
    다른 서비스에서 접근을 허용하기위해 @CrossOrigin을 추가해주었다.

    package com.example.jwt.jwtController;

    import com.example.jwt.service.JwtService;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.web.bind.annotation.CrossOrigin;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.PostMapping;
    import org.springframework.web.bind.annotation.RestController;

    import javax.servlet.http.HttpServletRequest;

    @RestController
    @CrossOrigin
    public class JwtController {

        @Autowired
        private JwtService jwtService;

        @PostMapping("/jwt/create")
        public String createJwt(HttpServletRequest res) throws Exception {

            return jwtService.makeJwt(res);
        }

        @GetMapping("/jwt/auth")
        public boolean authToken(HttpServletRequest res) throws Exception {
            String jwt = res.getParameter("jwt");

            if(jwt == null) {
                return false;
            }else {
                return jwtService.checkJwt(jwt);
            }
        }
    }

모두 POST방식으로 해야하지만 테스트하기 쉽도록 인증때는 GET방식을 이용하였다.
우선 createJwt 메소드는 이름과 같이 Jwt를 생성해주는 메소드이다.
authToken 메소드는 받은 jwt가 인증된 토큰인지 검사하는 메소드이다.

서비스

package com.example.jwt.service.impl;

import com.example.jwt.service.JwtService;
import io.jsonwebtoken.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

import javax.crypto.spec.SecretKeySpec;
import javax.servlet.http.HttpServletRequest;
import javax.xml.bind.DatatypeConverter;
import java.security.Key;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

@Service
public class JwtServiceImpl implements JwtService {

    private String secretKey = "ThisisHyoJunSecretKeyWelcomeMyFirstJwt";

    private Logger logger = LoggerFactory.getLogger(JwtServiceImpl.class);

    @Override
    public String makeJwt(HttpServletRequest res) throws Exception {
        SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256;
        Date expireTime = new Date();
        expireTime.setTime(expireTime.getTime() + 1000 * 60 * 1);
        byte[] apiKeySecretBytes = DatatypeConverter.parseBase64Binary(secretKey);
        Key signingKey = new SecretKeySpec(apiKeySecretBytes, signatureAlgorithm.getJcaName());

        Map<String, Object> headerMap = new HashMap<String, Object>();

        headerMap.put("typ","JWT");
        headerMap.put("alg","HS256");

        Map<String, Object> map= new HashMap<String, Object>();

        String name = res.getParameter("name");
        String email = res.getParameter("email");

        map.put("name", name);
        map.put("email", email);

        JwtBuilder builder = Jwts.builder().setHeader(headerMap)
                .setClaims(map)
                .setExpiration(expireTime)
                .signWith(signatureAlgorithm, signingKey);

        return builder.compact();
    }

    @Override
    public boolean checkJwt(String jwt) throws Exception {
        try {
            Claims claims = Jwts.parser().setSigningKey(DatatypeConverter.parseBase64Binary(secretKey))
                    .parseClaimsJws(jwt).getBody(); // 정상 수행된다면 해당 토큰은 정상토큰

            logger.info("expireTime :" + claims.getExpiration());
            logger.info("name :" + claims.get("name"));
            logger.info("Email :" + claims.get("email"));

            return true;
        } catch (ExpiredJwtException exception) {
            logger.info("토큰 만료");
            return false;
        } catch (JwtException exception) {
            logger.info("토큰 변조");
            return false;
        }
    }
}

makeJwt 메소드를보면 헤더에 alg와 typ를 설정해주었고,
클레임에는 비공개클레임으로 간단히 email과 name을 설정해주었다.
또한 만료시간으로는 1분으로 잡았다.


아래에 checkJwt메소드에서는 try문에서 받아온 Jwt를 이용하여 파싱을하는데 여기서 파싱이 된다면
정상적인 토큰으로 간주하고 여기서 파싱이 되지 않는다면 catch문에 잡힐 것이다.

매우 간단하게 Jwt를 생성하고 Jwt를 인증하는 방법을 소개해보았다. 사실은 더 복잡하게 구현해야하지만 나도 공부중이므로 계속해서 보강하도록 할 것이다.

테스트는 POSTMAN이라는 프로그램을 통해 할 수 있다. POSTMAN은 간단히 API를 날려볼 수 있고 결과값을 받을 수 있는 무료 프로그램이다.

생성된 JWT는 jwt.io에서 확인해볼수 있다.

효준's profile image

효준

2018-07-17 18:03

다른글 보러가기

JWT(Json Web Token)

이전 포스트

인텔리j 단축키 모음

다음 포스트