[JWT] JWT 인증 방식을 더 자세히 알아보자
JWT(Json Web Token)를 가지고 클라이언트와 서버는 어떻게 주고 받는지, 그리고 무엇을 보고 검증하는 지 알아보자
Sep 03, 2024
1. 사용자 인증 과정💻 클라이언트 측: 로그인 요청🛠️ 서버 측: 자격 증명 검증 및 JWT 생성2. JWT 전송 과정💻 클라이언트 측: JWT 저장 및 전송3. 서버 측 JWT 검증 및 사용자 인증🛠️ 서버 측: JWT 검증🔐 서버 측: 사용자 인증 처리4. 요청 처리 및 응답
1. 사용자 인증 과정
💻 클라이언트 측: 로그인 요청
먼저 사용자는 로그인 화면을 통해 자신의 자격 증명(주로 사용자 이름과 비밀번호)을 클라이언트에 입력한다. 클라이언트 애플리케이션(예: 웹 브라우저 또는 모바일 앱)은 이 자격 증명을 서버로 전달하기 위해 다음과 같은 HTTP POST 요청을 전송한다:
POST /login Content-Type: application/json { "username": "johndoe", "password": "mypassword" }
🛠️ 서버 측: 자격 증명 검증 및 JWT 생성
서버는 이 요청을 받아서 전달된 자격 증명이 유효한지 확인한다. 이 과정은 보통 데이터베이스에서 사용자의 정보(사용자 이름과 비밀번호)를 조회하여 이루어진다. 만약 자격 증명이 올바르면, 서버는 해당 사용자에 대한 JWT를 생성한다.
// 사용자 인증이 성공하면 서버는 JWT를 생성한다 String jwtToken = jwtUtil.generateToken(username);
이때 서버는 사용자의 ID, 이름, 역할(role) 등 필요한 정보를 JWT의 페이로드에 포함시킨다. 생성된 JWT는 이후 클라이언트에 전달된다:
HTTP/1.1 200 OK Content-Type: application/json { "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..." }
이 JWT는 다음과 같은 정보를 포함할 수 있다:
{ "sub": "johndoe", "iat": 1622567280, "exp": 1622570880, "roles": ["ROLE_USER"] }
여기서:
sub
: JWT의 주체로, 보통 사용자의 ID 또는 사용자명을 나타낸다.
iat
: JWT 발급 시간(Unix 타임스탬프)이다.
exp
: JWT 만료 시간(Unix 타임스탬프)으로, 이 시간이 지나면 토큰이 더 이상 유효하지 않다.
roles
: 사용자의 역할을 나타내며, 이를 통해 서버는 사용자의 권한을 판단할 수 있다.
2. JWT 전송 과정
💻 클라이언트 측: JWT 저장 및 전송
클라이언트는 서버로부터 받은 JWT를 저장한다. 일반적으로 웹 애플리케이션에서는 JWT를 브라우저의 로컬 스토리지나 세션 스토리지에 저장한다. 이후 클라이언트가 서버에 요청을 보낼 때마다 이 JWT를 HTTP 헤더에 포함시킨다:
GET /api/protected-resource Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
이때
Authorization
헤더의 값으로 Bearer <token>
형식을 사용하며, 여기서 <token>
은 실제 JWT이다.3. 서버 측 JWT 검증 및 사용자 인증
🛠️ 서버 측: JWT 검증
서버는 클라이언트로부터 요청을 받을 때마다, 해당 요청에 포함된 JWT를 검증하여 유효한 사용자인지 확인한다. 이 과정에서 서버는 다음과 같은 작업을 수행한다:
- JWT 추출: 서버는 요청의
Authorization
헤더에서 JWT를 추출한다.
String token = request.getHeader("Authorization").substring(7);
- 서명 검증: 서버는 JWT의 서명을 확인하여 토큰이 변조되지 않았는지 검증한다. 서명 검증은 토큰의 서명을 생성할 때 사용한 비밀 키를 이용해 수행된다.
Claims claims = Jwts.parser() .setSigningKey(secretKey) .parseClaimsJws(token) .getBody();
- 만료 시간 확인: 서버는 JWT의
exp
클레임을 확인하여 토큰이 만료되었는지 검사한다. 만료 시간이 현재 시간보다 이전이라면, 토큰은 무효화된다.
Date expiration = claims.getExpiration(); if (expiration.before(new Date())) { throw new JwtException("Token is expired"); }
- 사용자 정보 추출: JWT가 유효한 경우, 서버는 토큰의 페이로드에서 사용자 정보를 추출하고, 이를 통해 요청을 보낸 사용자가 누구인지 식별한다.
String username = claims.getSubject();
🔐 서버 측: 사용자 인증 처리
서버는 JWT의 검증이 성공하면, 페이로드에서 추출한 사용자 정보(예: 사용자명, 역할 등)를 이용해 요청을 처리한다. 이 정보는 보통 보안 컨텍스트에 저장되어 이후 요청을 처리하는 데 사용된다.
예를 들어, 서버는 사용자가 특정 API에 접근할 권한이 있는지를 JWT에 포함된
roles
클레임을 통해 확인할 수 있다. 만약 사용자가 권한이 없는 리소스에 접근하려고 하면, 서버는 접근을 거부한다.4. 요청 처리 및 응답
JWT 검증이 완료되고 사용자가 인증되면, 서버는 요청을 처리하고, 결과를 클라이언트에 응답으로 반환한다. 이때 응답은 일반적인 HTTP 응답과 동일하며, 특별히 JWT와 관련된 정보는 포함되지 않는다.
HTTP/1.1 200 OK Content-Type: application/json { "data": "protected information" }
Share article