1. 개요
JWT를 이용한 인증 방법 구현하기 위해 공부한 내용.
2. 개념
암호화된 Json 형식의 토큰을 의미한다. 주로 인증에 사용한다. session과 달리 매 요청마다 전달되기 때문에 서버의 부담이 줄어든다.
2.1 구조
- 아래 예시처럼 Header, Payload, Signature로 구분된다.
- HEADER
{
"alg": "HS256",
"typ": "JWT"
}
- PAYLOAD:DATA
{
"sub": "1234567890",
"name": "John Doe",
"iat": 1516239022
}
- SIGNATURE
HMACSHA256(
base64UrlEncode(header) + "." +
base64UrlEncode(payload),
) secret base64 encoded
- 암호화되면 아래 구조로 바뀐다.
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
3. 어떻게 동작하는가?
3.1 로그인 시 JWT 사용 과정
- 클라이언트는 Post로 id와 password를 보낸다.
- 서버는 id와 password 유효성을 확인하고 userId를 답은 JWT를 만든다.
- 서버는 만든 jwt를 클라이언트에 전달한다.
- 이후 로그인에는 클라이언트 요청에 JWT가 담아서 온다.
- 서버는 JWT의 signature의 유효성을 검사한다.
- 유효성 검사가 jwt만들 때 넣었던 key인가?
- payload 속 사용자의 ID 추출한다.
- 이 아이디가 로그인됐다는 것을 파악한다.
JWT 토큰으로 만드는 법
@GetMapping("/hello")
public String hello() {
String key = "A";
String userId = "guswns1659";
Map<String, Object> headers = new HashMap<>();
headers.put("typ", "JWT");
headers.put("alg", "HS256");
Map<String, Object> payloads = new HashMap<>();
Long expiredTime = 1000 * 60L;
Date now = new Date();
now.setTime(now.getTime() + expiredTime);
payloads.put("exp", now);
payloads.put("userId", userId);
this.jwt = Jwts.builder()
.setHeader(headers)
.setClaims(payloads)
.signWith(SignatureAlgorithm.HS256, key.getBytes())
.compact();
return this.jwt;
}
JWT 토큰을 Parsing하는 법
@GetMapping("jwtParsing")
public String jwtParsing() {
Claims claims = Jwts.parser()
.setSigningKey("A".getBytes())
.parseClaimsJws(this.jwt)
.getBody();
return claims.get("userId", String.class);
}
Session과 차이점
1. session
- Session에 정보가 많으면 메모리를 많이 잡아먹는다.
- 정보가 적으면 자주 DB에 접근해야 하니 비용이 비싸다.
2. 차이점
Session을 이용하는 경우 처음 로그인할 때 쿠키에 로그인한 사용자의 세션id를 담아서 응답한다. 이 후 서버는 쿠키에 담긴 사용자의 세션id를 통해 로그인했다는 것을 파악한다.
jjwt 사용법
parsing
- request
`http http:``//localhost``:8080``/parser``?jwt=eyJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJTdG9ybXBhdGgiLCJzdWIiOiJtc2lsdmVybWFuIiwibmFtZSI6Ik1pY2FoIFNpbHZlcm1hbiIsInNjb3BlIjoiYWRtaW5zIiwiaWF0IjoxNDY2Nzk2ODIyLCJleHAiOjQ2MjI0NzA0MjJ9.kP0i_RvTAmI8mgpIkDFhRX3XthSdP-eqqFKGcU92ZIQ`
`@RequestMapping``(value =` `"/parser"``, method = GET)`
`public` `JwtResponse parser(``@RequestParam` `String jwt)` `throws` `UnsupportedEncodingException {`
`Jws<Claims> jws = Jwts.parser()`
`.setSigningKeyResolver(secretService.getSigningKeyResolver())`
`.parseClaimsJws(jwt);`
`return` `new` `JwtResponse(jws);`
`}`
컨트롤러에서 쿠키를 설정하고 보내는 법
@RequestMapping(value="/some/path", method = RequestMethod.POST)public void ResponseEntity<?> someMethod(**HttpServletResponse response**) { Cookie myCookie = new Cookie("cookieName", cookieValue);
myCookie.setMaxAge(쿠키 expiration 타임 (int));
myCookie.setPath("/"); // 모든 경로에서 접근 가능 하도록 설정
response.addCookie(myCookie);
}
인터셉트
- 넘어오는 jwt를 키를 확인(유효성)을 확인한 뒤 일치하지 않는 키라면 예외처리하고 컨트롤러에 보내지 않는다.
- jwt를 header와 set-cookie 중 어디로 올 지, 모르니까 둘 다 확인해도 된다.
'프로그래밍' 카테고리의 다른 글
20.04.07) tree 설치하는 법 (0) | 2020.04.08 |
---|---|
20.02.19) IntelliJ 단축키 및 사용법 (0) | 2020.02.19 |
19.11.03) 컴퓨터의 구성요소와 이진법 (0) | 2019.12.13 |