티스토리 뷰
📚 토큰 기반 인증 시스템?
JWT는 서버 기반 인증과는 다르게 토큰을 이용한 토큰 기반 인증 시스템입니다.
토큰 기반 인증 시스템을 선택해야 하는 이유는 다음과 같습니다.
1. 무상태성!
stateless서버는 상태를 유지하지 않고, 서버는 클라이언트 측에서 들어오는 요청만으로 작업을 처리합니다. 따라서 클라이언트와 서버의 연결고리가 없기 때문에 서버의 확장성이 높아집니다.
2. 무결성!
안전한 API를 만들기 위해 쿠키 같은 인증 시스템을 사용하지 않아도 됩니다.
3. 확장성!
토큰 기반 인증을 사용하는 다르 시스템에 접근이 가능합니다. 대표적인 예제로는 OAuth가 있으며, 페이스북/구글 같은 소셜 계정들을 이용하여 다른 웹 서비스에서도 로그인할 수 있습니다.
4. 보안성!
토큰 기반 인증 시스템을 사용하여 애플리케이션의 보안을 높일 수 있습니다.
다만, 토큰 기반 인증을 사용한다고 해서 무조건 해킹의 위험에서 벗어나는 것은 아닙니다.
🔍 JWT?
그렇다면, 토큰 기반 인증 시스템인 JWT는 무엇일까요?
JWT는 토큰 기반 인증 시스템의 대표적인 구현체입니다. Java를 포함한 많은 프로그래밍 언어에서 지원하며, 보통 회원 인증을 할 때 자주 사용됩니다. JWT(JSON Web Token)은 웹 표준(RFC7519)으로 대부분 언어, 플랫폼에 독립적으로 사용할 수 있는 장점이 있습니다.
JWT는 헤더(header), 내용(payload), 서명(signature)으로 구성됩니다.
- header : 토큰의 타입과 해시 암호화 알고리즘으로 구성됩니다.
- payload : userid, expire, scope 등의 정보가 담깁니다.
- signature에는 secret key를 포함하며 암호화되어있습니다.
JWT의 동작 절차는 쿠키와 유사하며 다음과 같은 순서로 동작합니다.
- 클라이언트는 인증을 위해 ID와 Password를 서버에 전달한다.
- 서버는 클라이언트의 정보 확인 후 인증 정보를 JWT로 클라이언트에 보낸다.
- 클라이언트는 이 정보를 저장하기 위해 storage 등을 사용한다.
- 이후 필요한 API 호출 시 JWT를 함께 전달한다.
- REST API를 제공하는 서버는 JWT가 적절한지 검증 후 호출한 API 결과를 반환한다.
📙 SpringBoot에 적용
1. 의존성 추가
implementation 'io.jsonwebtoken:jjwt:0.9.1'
2. JWT 토큰 만들기
public String makeJwtToken() {
Date now = new Date();
return Jwts.builder()
.setHeaderParam(Header.TYPE, Header.JWT_TYPE) // (1)
.setIssuer("fresh") // (2)
.setIssuedAt(now) // (3)
.setExpiration(new Date(now.getTime() + Duration.ofMinutes(30).toMillis())) // (4)
.claim("id", "아이디") // (5)
.claim("email", "gpfls0506@gmail.com")
.signWith(SignatureAlgorithm.HS256, "secret") // (6)
.compact();
}
3. JWT 토큰 파싱 하기
클라이언트에서 토큰을 저장해두었다가 Authrization 헤더에 Bearer라는 문자열을 붙여 토큰을 보냅니다.
전달받은 토큰을 해석해서 유효한 토큰인지를 확인합니다.
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws IOException, ServletException {
String authorizationHeader = request.getHeader(HttpHeaders.AUTHORIZATION);
Claims claims = jwtTokenProvider.parseJwtToken(authorizationHeader);
filterChain.doFilter(request, response);
}
public Claims parseJwtToken(String authorizationHeader) {
validationAuthorizationHeader(authorizationHeader); // (1)
String token = extractToken(authorizationHeader); // (2)
return Jwts.parser()
.setSigningKey("secret") // (3)
.parseClaimsJws(token) // (4)
.getBody();
}
private void validationAuthorizationHeader(String header) {
if (header == null || !header.startsWith("Bearer ")) {
throw new IllegalArgumentException();
}
}
private String extractToken(String authorizationHeader) {
return authorizationHeader.substring("Bearer ".length());
}
헤더가 "Bearer"로 시작하는지 검사하고, "Bearer"을 제외한 문자열만 반환해주도록 처리합니다.
시크릿 키를 넣어주어 토큰을 해석할 수 있고, 해석할 토큰을 문자열 형태로 넣어줍니다.
📈 Refresh Token
더 나아가 Refresh Token에 대해서 알아보겠습니다.
JWT는 세션을 사용할 수 없는 REST 환경에서 세션처럼 인증 정보를 유지하기 위해서 사용됩니다.
세션의 경우는 활동에 따라서 유효기간이 연장되지만, 토큰의 경우는 만들어진 시점에 이미 유효기한이 정해져 있습니다.
이렇게 정해진 토큰의 유효기간은 자체적으로 연장되지 않습니다. 따라서 장기간 사용해야 하는 경우는 번거로움이 생기게 됩니다.
이러한 문제는 상대적으로 긴 유효기간을 가지는 Refresh Token을 두어서 auth token의 단점을 보완할 수 있습니다.
로그인 상황에서 달라진 점은 기존의 auth token과 함께 refresh token을 생성합니다.
refresh token은 auth token과 달리 토큰에 사용자를 특정할 수 있는 정보(email 등)를 저장하지 않습니다. 단지 유효한 토큰인지만 확인하면 되고, 따라서 탈취되더라도 큰 부담은 없습니다.
따라서 autho token 대비 긴 유효기간을 갖게 되며, auth token정보는 서버 측에 저장되는 것이 없지만 refresh token은 서버에 사용자를 구분할 수 있는 정보와 함께 저장해둡니다.
1시간이 경과 후 auth token의 유효기간이 만료된 토큰으로 서버에 정보를 요청하면 서버에서는 401 오류를 반환시킵니다.
401 오류를 받은 클라이언트는 refresh token을 전달하면서 auth token 갱신을 요청하고, 서버는 refresh token이 유효한지 확인 후 기존에 저장하고 있던 refresh tokens와 같다면 새로운 auth token을 발행해줍니다.
클라이언트는 새로운 auth token을 저장하고 이를 이용해서 서비스를 받게 됩니다.
'Programming > BackEnd' 카테고리의 다른 글
[Back] Lombok 롬복 (JAVA) (0) | 2022.04.14 |
---|---|
[Web] 세션과 쿠키 (Session & Cookie) (0) | 2022.04.08 |
- Total
- Today
- Yesterday
- springboot
- Retrofit2
- dp
- 조합
- subset
- 부분집합
- BFS
- BOJ
- Java
- 토큰기반인증
- IMAGE
- 아이템59
- bruteforce
- 백준
- 완전탐색
- 그래프탐색
- 이펙티브자바
- dfs
- OS
- 아이템60
- 완탐
- docker-compose
- 알고리즘
- 운영체제
- 정처기
- EffectiveJava
- Container
- 순열
- docker
- 아이템61
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |