[SpringBoot] JWT 토큰 구현 및 활용

2025. 3. 6. 14:53·SpringBoot

로그인 기능을 개발하면서 사용자 인증의 핵심 요소인 JWT(JSON Web Token)를 본격적으로 도입하게 되었다. 기존의 세션 방식에서 벗어나 더욱 안전하고 확장성 있는 인증 메커니즘을 구현하고 싶었다. 이 글에서는 내가 실제 프로젝트에서 JWT를 어떻게 구현하고 활용했는지 상세히 공유하려 한다.

 

JWT란?

당사자 간에 정보를 JSON 객체로 안전하게 전송하기 위한 간결하고 자가수용적인 방식이다. 주로 인증과 정보 교환에 사용되며, 세 부분으로 구성된다.

  1. Header(헤더)
    • 토큰의 유형과 해시 알고리즘 정보를 포함한다.
    • 예: 사용된 해시 알고리즘(HMAC SHA256), 토큰 타입(JWT)
  2. Payload(페이로드)
    • 토큰에 담길 정보(클레임)를 포함한다.
    • 사용자 ID, 이름, 만료 시간 등 다양한 데이터 저장 가능
  3. Signature(서명)
    • 토큰의 무결성을 보장하는 부분이다.
    • 헤더, 페이로드, 비밀 키를 사용하여 생성

JWT를 사용하는 이유

  1. 상태 비저장(Stateless) 인증
    • 서버가 세션을 저장하지 않고 토큰만으로 인증 가능
    • 서버 확장성과 마이크로서비스 아키텍처에 적합
  2. 보안성
    • 디지털 서명으로 데이터 변조 방지
    • 토큰 자체에 만료 시간 포함으로 보안 강화
  3. 크로스 도메인 인증
    • 모바일 앱, 웹 서비스 등 다양한 플랫폼에서 쉽게 인증 가능
    • RESTful API 인증에 이상적
  4. 확장성
    • 추가 정보를 쉽게 토큰에 포함 가능
    • 클라이언트와 서버 간 정보 교환에 유연

JWT 사용 예시

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.   // 헤더
eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.   // 페이로드
SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c   // 서명

 

JWT 유틸리티 클래스 구현

JWT 유틸리티 클래스의 주요 구성

public class JwtUtil {
    // 비밀 키와 만료 시간 설정
    private static final String SECRET_KEY = "1234"; // 실제 환경에서는 보다 복잡한 키 사용 권장
    private static final long EXPIRE_TIME = 1000 * 60 * 60; // 1시간 유효 시간
}

JWT 구현의 첫 단계로 비밀 키와 토큰 만료 시간을 설정했다. 비밀 키는 토큰 서명에 사용되며, 만료 시간은 보안을 위해 1시간으로 제한했다.

토큰 생성 메서드

private static String createToken(String tokenSuject) {
    return JWT.create()
        .withSubject("" + tokenSuject) // 토큰의 주체 (사용자 번호)
        .withExpiresAt(new Date(System.currentTimeMillis() + EXPIRE_TIME)) // 만료 시간 설정
        .sign(Algorithm.HMAC512(SECRET_KEY)); // HMAC512 알고리즘으로 서명
}

토큰 생성 메서드에서는 다음과 같은 중요한 작업을 수행한다.

  • 토큰의 주체(Subject)로 사용자 번호 설정
  • 현재 시간 기준 1시간 후를 만료 시간으로 지정
  • HMAC512 알고리즘을 사용하여 비밀 키로 토큰 서명

토큰 검증 및 추출 메서드

public static boolean checkToken(String token) {
    try {
        JWTVerifier verifier = JWT.require(Algorithm.HMAC512(SECRET_KEY)).build();
        verifier.verify(token); // 토큰 검증
        System.out.println("토큰이 유효합니다.");
        return true;
    } catch (JWTVerificationException exception) {
        System.out.println("토큰이 유효하지 않습니다.");
        return false;
    }
}

토큰 검증 메서드는 다음과 같은 기능을 수행한다:

  • 동일한 비밀 키로 토큰 검증
  • 토큰의 유효성, 만료 여부 확인
  • 유효하지 않은 경우 예외 처리

로그인 컨트롤러에서의 JWT 토큰 활용

일반 로그인 시 토큰 발급

@PostMapping("/api/users/login")
public JsonResult login(@RequestBody JuLoginVo juLoginVo, HttpServletResponse response) {
    JuLoginVo authUser = juUserService.exeLogin(juLoginVo);
    if (authUser != null) {
        // 업체 계정 활성화 검증
        if ("업체".equals(authUser.getType()) && !authUser.isIs_active()) {
            return JsonResult.fail("승인되지 않은 계정입니다. 관리자에게 문의하세요.");
        }
        // JWT 토큰 생성 및 응답 헤더 설정
        JwtUtil.createTokenAndSetHeader(response, "" + authUser.getMember_id());
        return JsonResult.success(authUser);
    } else {
        return JsonResult.fail("아이디 또는 비밀번호가 잘못되었습니다.");
    }
}

로그인 과정에서 다음과 같은 JWT 토큰 발급 절차를 구현했다.

  • 로그인 성공 시 사용자 ID로 JWT 토큰 생성
  • 응답 헤더의 Authorization에 "Bearer {토큰}" 형식으로 토큰 추가
  • 추가 보안을 위해 업체 계정의 경우 활성화 상태 확인

 

소셜 로그인 시 토큰 발급

@PostMapping("/api/users/social/signup")
public JsonResult socialSignUp(@RequestBody JuUserVo juUserVo, HttpServletResponse response) {
    try {
        // 소셜 회원가입 처리
        int count = juUserService.exeSocialSignUp(juUserVo);
        if (count != 1) {
            return JsonResult.fail("회원등록에 실패했습니다.");
        }
        
        // 회원 정보 조회
        JuLoginVo authUser = juUserService.exeSocialLogin(juUserVo.getEmail());
        if (authUser != null) {
            // JWT 토큰 생성 및 응답 헤더 설정
            JwtUtil.createTokenAndSetHeader(response, "" + authUser.getMember_id());
            return JsonResult.success(authUser);
        } else {
            return JsonResult.fail("회원가입은 성공했으나 사용자 정보를 가져올 수 없습니다.");
        }
    } catch (Exception e) {
        return JsonResult.fail("회원가입 처리 중 오류 발생: " + e.getMessage());
    }
}

소셜 로그인에서도 동일한 JWT 토큰 발급 방식을 적용했다.

  • 소셜 회원가입 성공 후 회원 정보 조회
  • 조회된 사용자 ID로 JWT 토큰 생성
  • 응답 헤더에 토큰 추가

 

마무리

JWT 토큰 구현을 통해 다음과 같은 이점을 얻을 수 있었다.

  • 안전하고 확장 가능한 사용자 인증 메커니즘
  • 상태 비저장(Stateless) 인증 방식 구현
  • 토큰 만료 및 보안 설정을 통한 보안성 강화

개발 과정에서 주의해야 할 점은 실제 운영 환경에서는 더욱 복잡하고 안전한 비밀 키를 사용해야 한다는 것이다.

'SpringBoot' 카테고리의 다른 글

[SpringBoot] sts4 설치 및 압축풀기 오류 해결  (0) 2025.04.24
[SpringBoot] 일관된 API 응답을 위한 JsonResult 구현 및 활용  (0) 2025.03.07
[SpringBoot] 스프링부트 어노테이션(Annotation) 정리  (0) 2025.03.05
[SpringBoot]AWS S3를 활용한 파일 업로드 구현하기  (0) 2025.02.28
[SpringBoot] Twilio를 활용한 기념일 알림 기능 개발  (0) 2025.02.23
'SpringBoot' 카테고리의 다른 글
  • [SpringBoot] sts4 설치 및 압축풀기 오류 해결
  • [SpringBoot] 일관된 API 응답을 위한 JsonResult 구현 및 활용
  • [SpringBoot] 스프링부트 어노테이션(Annotation) 정리
  • [SpringBoot]AWS S3를 활용한 파일 업로드 구현하기
dud9902
dud9902
개발자 취준생 기록일지
  • dud9902
    dud's DevStory
    dud9902
  • 전체
    오늘
    어제
    • 분류 전체보기 (79)
      • SpringBoot (14)
      • React (12)
      • Python (14)
      • AI (21)
      • DB (5)
      • Figma (1)
      • Markdown (1)
      • AWS (6)
      • 기타 (5)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

  • 공지사항

  • 인기 글

  • 태그

    twilio
    Python
    CrewAI
    springboot
    Agent
    miniforge
    docker
    react
    langchain
    스프링부트
    redis
    db
    의존성 주입
    pydantic
    FastAPI
    AWS
    recognize anything
    pytorch
    SQLAlchemy
    AI
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.3
dud9902
[SpringBoot] JWT 토큰 구현 및 활용
상단으로

티스토리툴바