OPEN HYPER STEP
← 목록으로 (Java+Spring)
JAVA · 71 / 99
java
CHAPTER 71 / 99
읽기 약 2
FUNCTION

JWT 인증 시스템 구축


핵심 개념

JWT 구조·생성/검증·Refresh 토큰·Spring Security 통합 — REST API 표준 인증.

본문

JWT 구조

📋 코드 (5줄)
header.payload.signature

Header:    {"alg": "HS256", "typ": "JWT"}
Payload:   {"sub": "user123", "exp": 1234567890, "role": "USER"}
Signature: HMAC-SHA256(base64(header) + "." + base64(payload), secret)

JWT 생성/검증

JAVA📋 코드 (41줄)
// build.gradle: implementation 'io.jsonwebtoken:jjwt-api:0.12.5'

@Component
@RequiredArgsConstructor
public class JwtUtil {
    private final Key secretKey;

    public JwtUtil(@Value("${jwt.secret}") String secret) {
        this.secretKey = Keys.hmacShaKeyFor(secret.getBytes());
    }

    public String generate(String username, String role) {
        Date now = new Date();
        Date exp = new Date(now.getTime() + 1000 * 60 * 30);  // 30분

        return Jwts.builder()
            .setSubject(username)
            .claim("role", role)
            .setIssuedAt(now)
            .setExpiration(exp)
            .signWith(secretKey, SignatureAlgorithm.HS256)
            .compact();
    }

    public Claims parse(String token) {
        return Jwts.parserBuilder()
            .setSigningKey(secretKey)
            .build()
            .parseClaimsJws(token)
            .getBody();
    }

    public boolean isValid(String token) {
        try {
            parse(token);
            return true;
        } catch (JwtException e) {
            return false;
        }
    }
}

JWT 필터

JAVA📋 코드 (28줄)
@Component
@RequiredArgsConstructor
public class JwtAuthFilter extends OncePerRequestFilter {
    private final JwtUtil jwtUtil;

    @Override
    protected void doFilterInternal(HttpServletRequest req,
                                     HttpServletResponse res,
                                     FilterChain chain) throws ServletException, IOException {
        String header = req.getHeader("Authorization");
        if (header != null && header.startsWith("Bearer ")) {
            String token = header.substring(7);
            if (jwtUtil.isValid(token)) {
                Claims claims = jwtUtil.parse(token);
                String username = claims.getSubject();
                String role = claims.get("role", String.class);

                var auth = new UsernamePasswordAuthenticationToken(
                    username,
                    null,
                    List.of(new SimpleGrantedAuthority("ROLE_" + role))
                );
                SecurityContextHolder.getContext().setAuthentication(auth);
            }
        }
        chain.doFilter(req, res);
    }
}

Refresh 토큰

JAVA📋 코드 (31줄)
@Service
@RequiredArgsConstructor
public class AuthService {
    private final JwtUtil jwtUtil;
    private final RedisTemplate<String, String> redis;

    public TokenPair login(String username, String password) {
        // ... 비밀번호 검증

        String accessToken = jwtUtil.generate(username, "USER");
        String refreshToken = UUID.randomUUID().toString();

        // Redis에 refresh 토큰 저장 (7일)
        redis.opsForValue().set(
            "refresh:" + refreshToken,
            username,
            Duration.ofDays(7)
        );

        return new TokenPair(accessToken, refreshToken);
    }

    public String refresh(String refreshToken) {
        String username = redis.opsForValue().get("refresh:" + refreshToken);
        if (username == null) {
            throw new InvalidRefreshTokenException();
        }
        // 새 access 토큰 발급
        return jwtUtil.generate(username, "USER");
    }
}

컨트롤러

JAVA📋 코드 (16줄)
@RestController
@RequiredArgsConstructor
public class AuthController {
    private final AuthService authService;

    @PostMapping("/auth/login")
    public TokenPair login(@RequestBody LoginRequest req) {
        return authService.login(req.username(), req.password());
    }

    @PostMapping("/auth/refresh")
    public AccessTokenResponse refresh(@RequestBody RefreshRequest req) {
        String newAccess = authService.refresh(req.refreshToken());
        return new AccessTokenResponse(newAccess);
    }
}

다음 챕터

CH.3 "OAuth2 소셜 로그인" — Google/Kakao 연동.


AI 프롬프트
🤖 AI에게 잘 물어보는 법 — 모델·전략별 프롬프트
Claude

무료: Sonnet 4.6 / Pro $20/mo: Opus 4.6

내 Spring 코드의 JWT 인증 부분을 분석해서
토큰 만료·revoke 전략와 개선 우선순위를 알려줘.
ChatGPT

무료: GPT-5.5 / Plus $20/mo: GPT-5.5 Pro

JWT 인증 vs 다른 패턴 비교를
실전 사례 5개로 보여주고 JWT vs Session 트레이드오프를 알려줘.
Gemini

무료: 2.5 Flash / Pro $19.99/mo: 3.1 Pro

내 코드베이스 전체를 분석해서
JWT 인증 관련 토큰 검증 누락 위치를 보고해줘.
Grok

무료: Grok 4.1 / SuperGrok $30/mo

2026년 한국 기업의 JWT 인증 채택률과
한국 SaaS의 JWT 채택 패턴를 솔직히 알려줘.

⭐ 이것만 기억하세요
JWT 인증 시스템 구축 이 3가지만 확실히 잡으세요
1.JWT는 stateless — 서버 세션 불필요, 수평 확장 쉬움
2.Refresh 토큰은 Redis에 저장 + 짧은 access 토큰으로 보안과 UX 균형
3.다음 챕터 CH.3에서 OAuth2 — 소셜 로그인 표준


공유하기
진행도 71 / 99