JWT란?
Json Web Token
를 뜻하며 기업에서 많이 사용 중인 토큰 방식의 로그인 구현을 위한 토큰 발행 API이다. 예전에 프로젝트를 할 때 NodeJS
환경에서 발급하였는데 이번에는 Spring
에서 발급 및 해독하는 방법을 코드단위에서 알아보려고 한다.
JWT의 구성과 작동 방식은 다음번에 라이브러리 없이 직접 발행하는 과정을 실습하며 포스팅할 예정이다.
Project 환경
SpringBoot
Maven
Java 11
Dependency 설정
SpringBoot initializer
로 프로젝트 생성시에 JWT 관련 모듈을 미리 다운받아도 되고, xml
파일에 직접 작성해주고 리로드해도 상관없다. 글쓴이는 미리 생성해둔 프로젝트에 모듈을 미리 다운받지 않았기 때문에 다음과 같이 수동으로 코드를 추가해 주었다.
#pom.xml
<!-- JWT -->
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.9.1</version>
</dependency>
이로써 우리는 "Jwts
"라는 Api를 Spring
에서 사용할 수 있게 되었다.
JWT 토큰 생성
JWT
토큰은 Header
, Payload(claim)
, Signature
로 이루어져 있으며 최종 결과물에서 ".
"으로 구분한다. 자세한 내용은 다음 포스트에서 다룰 것이므로 이해가 안간다면 우선 외우자!
다음은 아까 추가하였던 Jwts
모듈을 호출하여 JWT
토큰을 생성하는 예제이다.
@Slf4j
@Controller
@RequestMapping("/v5")
public class JwtTestController {
@GetMapping("/jwt")
public String jwtTestForm() {
return "v5/jwtTest";
}
@PostMapping("/jwt")
public String successForm(Model model, @RequestParam String email, String username) {
//salt
String salt = "saaalt";
//make jwt header
Map<String, Object> jwtHeader = new HashMap<>();
jwtHeader.put("typ", "JWT");
jwtHeader.put("alg", "HS256");
jwtHeader.put("regDate", System.currentTimeMillis());
//make claim
Map<String, Object> claim = new HashMap<>();
claim.put("email", email);
claim.put("username", username);
String token = Jwts.builder()
.setSubject(email)
.setHeader(jwtHeader)
.setClaims(claim)
.signWith(SignatureAlgorithm.HS256, salt)
.compact();
model.addAttribute("token", token);
return "/v5/verifyTest";
}
}
본인은 v5/verifyTest
라는 jsp
페이지로 토큰을 내려주어 시각적으로 확인하기 위한 컨트롤러를 작성하였다. (아무 설명없이 토큰 발행 코드만 제시하면 오해의 소지가 있을 것 같아 컨트롤러 전문을 가져왔다.)
발행시에는 위에서 언급했던 Header
, Payload(claim)
, Signature
를 만들어주는 과정이 들어간다.
Header
에는 이 토큰이 JWT 토큰임을 밝히며(typ
) 내가 사용하고 싶은 시그니처의 암호화 방식(alg
)을 명시한다.
Payload(claim)
부분에서는 내가 실제로 이 유저를 식별할 수 있는 "최소한" 의 정보만 담아준다. "최소한" 이라고 한 이유는 JWT
는 앞의 두 정보 즉 헤더와 페이로드를 단순히 base64 방식으로만 인코딩해서 전달하고 실질적인 암호화는 Signature
부분에서만 일어나기 때문에 유저 민감 정보를 "절대로" 담아서 서비스 하면 안된다.
JWT 토큰 해독
토큰 해독도 마찬가지로 Jwts
모듈에서 Signature
를 만들때 사용했던 secret key(salt)
를 첨가해주면 된다.
@Controller
@RequestMapping("/v5")
public class JwtVerifyController {
@PostMapping("/verify")
public String verifyJWT(Model model, @RequestParam String token) {
Claims verified = Jwts.parser().setSigningKey("saaalt").parseClaimsJws(token).getBody();
model.addAttribute("userInfo", verified);
return "/v5/verifyResult";
}
}
마찬가지로 v5/verifyResult
라는 페이지에서 시각적으로 확인하기 위하여 컨트롤러를 작성하였다. 해독과정은 미리 다 지정해준 방식으로 되돌리기만 하면 되기 때문에 비교적 간단하다. 그리고 실험은 해보지 않았지만 HS256방식이 JWT의 디폴트 알고리즘이기 때문에 파싱과정에서 별다른 알고리즘을 기입하지 않아도 잘 작동했던것 같다. (예전에 NodeJS 에서는 SSL 인증서 방식으로도 해보았는데 그런과정이 없었기 때문에..)
3줄 요약
JWT
는 유명한 웹 토큰의 한 종류이다.Header
, Payload(claim)
, Signature
로 이루어져있다.payload
에 넣지 말자!