JWT 기반 로그인 과정의 구체적인 예시
아래는 JWT 기반 로그인 과정을 구체적인 데이터와 저장 방식을 포함하여 자세히 설명한 내용입니다. 회원가입부터 로그인, 토큰 저장 및 검증, API 요청까지의 흐름을 따라갑니다.
1. 회원가입
1.1 프론트엔드 (사용자 입력)
• 사용자 user1이 아래 정보를 입력:
{
"username": "user1",
"password": "password123",
"email": "user1@example.com"
}
• 프론트엔드는 이를 백엔드에 POST 요청:
POST /api/register
Content-Type: application/json
{
"username": "user1",
"password": "password123",
"email": "user1@example.com"
}
1.2 백엔드 (데이터 저장)
1. 비밀번호 암호화
• password123을 암호화하여 데이터베이스에 저장:
String hashedPassword = passwordEncoder.encode("password123");
• 암호화된 비밀번호 예: $2a$10$GzQ...
2. 사용자 정보 데이터베이스 저장
• 데이터베이스 테이블:
CREATE TABLE users (
id BIGINT AUTO_INCREMENT PRIMARY KEY,
username VARCHAR(50) UNIQUE,
password VARCHAR(100),
email VARCHAR(100)
);
• 저장된 데이터:
id username password email
1 user1 $2a$10$GzQ... user1@example.com
2. 로그인
2.1 프론트엔드 (사용자 로그인 요청)
• 사용자 user1이 아래 정보를 입력:
{
"username": "user1",
"password": "password123"
}
• 프론트엔드는 이를 백엔드에 POST 요청:
POST /api/login
Content-Type: application/json
{
"username": "user1",
"password": "password123"
}
2.2 백엔드 (인증 및 토큰 생성)
1. 사용자 정보 조회 및 검증
• 데이터베이스에서 username = 'user1'인 사용자 검색:
id username password email
1 user1 $2a$10$GzQ... user1@example.com
• 입력한 비밀번호(password123)와 저장된 암호화된 비밀번호를 비교:
passwordEncoder.matches("password123", "$2a$10$GzQ...");
결과: 일치함.
2. Access Token 생성
• JWT Access Token 생성:
String accessToken = Jwts.builder()
.setSubject("1") // 사용자 ID
.claim("username", "user1")
.setIssuedAt(new Date())
.setExpiration(new Date(System.currentTimeMillis() + 3600000)) // 1시간
.signWith(SignatureAlgorithm.HS256, secretKey)
.compact();
• 생성된 Access Token:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
3. Refresh Token 생성
• JWT Refresh Token 생성:
String refreshToken = Jwts.builder()
.setSubject("1") // 사용자 ID
.setIssuedAt(new Date())
.setExpiration(new Date(System.currentTimeMillis() + 604800000)) // 7일
.signWith(SignatureAlgorithm.HS256, secretKey)
.compact();
• 생성된 Refresh Token:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
4. Refresh Token 저장
• 데이터베이스에 Refresh Token 저장:
CREATE TABLE refresh_tokens (
id BIGINT AUTO_INCREMENT PRIMARY KEY,
user_id BIGINT NOT NULL,
token VARCHAR(500),
expiry_date TIMESTAMP
);
• 저장된 데이터:
id user_id token expiry_date
1 1 eyJhbGciOiJIUzI1NiIsInR... 2024-12-20 10:00:00
5. 토큰 반환
• Access Token은 응답 본문에 포함.
• Refresh Token은 HttpOnly 쿠키로 반환:
Set-Cookie: refreshToken=eyJhbGciOiJIUzI1NiIsInR...; HttpOnly; Secure
{
"accessToken": "eyJhbGciOiJIUzI1NiIsInR..."
}
3. 인증된 API 요청
3.1 프론트엔드 (Access Token 포함 요청)
• 프론트엔드는 Access Token을 Authorization 헤더에 포함하여 요청:
GET /api/user/profile
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR...
3.2 백엔드 (Access Token 검증)
1. 서명(Signature) 검증
• Access Token의 서명과 서버의 비밀 키(Secret Key)를 사용해 서명이 변조되지 않았는지 확인:
Claims claims = Jwts.parser()
.setSigningKey(secretKey)
.parseClaimsJws(accessToken)
.getBody();
2. 만료 시간(exp) 확인
• Access Token의 exp 값이 현재 시간보다 이후인지 확인:
Date expiration = claims.getExpiration();
if (expiration.before(new Date())) {
throw new ExpiredJwtException(...);
}
3. 요청 처리
• Access Token의 sub(사용자 ID)을 사용해 사용자 정보를 조회하고 응답:
{
"id": 1,
"username": "user1",
"email": "user1@example.com"
}
4. Access Token 만료
4.1 프론트엔드 (재발급 요청)
• 프론트엔드는 401 응답(Access Token 만료)을 받으면 Refresh Token으로 새로운 Access Token 요청:
POST /api/token/refresh
Content-Type: application/json
4.2 백엔드 (Refresh Token 검증 및 재발급)
1. Refresh Token 검증
• HttpOnly 쿠키로 전달된 Refresh Token을 검증:
• 서명(Signature) 확인.
• 만료 시간(exp) 확인.
• 데이터베이스 확인:
SELECT * FROM refresh_tokens WHERE token = 'eyJhbGciOiJIUzI1NiIsInR...';
2. 새로운 Access Token 생성
• Refresh Token이 유효하면 새로운 Access Token을 생성.
3. 새로운 Access Token 반환
• 클라이언트에 새로운 Access Token 반환:
{
"accessToken": "eyJhbGciOiJIUzI1NiIsInR..."
}
5. 최종 저장 및 흐름 요약
데이터 저장 위치
1. Access Token:
• 클라이언트 측에 저장 (로컬 스토리지, 세션 스토리지).
2. Refresh Token:
• 백엔드에서 데이터베이스에 저장 및 클라이언트의 HttpOnly 쿠키.
전체 흐름 요약
1. 회원가입:
사용자 정보(암호화된 비밀번호 포함)가 데이터베이스에 저장됨.
2. 로그인:
백엔드에서 Access Token과 Refresh Token을 생성. Refresh Token은 서버와 클라이언트 모두 저장.
3. API 요청:
Access Token으로 요청. 만료 시 Refresh Token으로 재발급.
4. Access Token 만료:
백엔드는 Refresh Token을 검증해 새로운 Access Token을 생성.
'spring' 카테고리의 다른 글
[Spring] Spring에서의 동기 비동기 (0) | 2025.01.06 |
---|---|
[Spring] Jackson (0) | 2024.12.17 |
[Spring] JPA 연관관계 (0) | 2024.12.04 |
[Spring] JPA (0) | 2024.12.03 |
[Spring] 프록시(proxy) (0) | 2024.11.30 |