웹 개발/Spring

Spring Security - JWT 인증 흐름과 @AuthenticationPrincipal, 토큰 응답 처리 정리

Blue_bull 2025. 4. 26. 00:01

1. JWT 인증과 @AuthenticationPrincipal 관계 정리

항목 타입 설명

JWT 토큰 String 예: "Bearer xxx.yyy.zzz" 형식. 클라이언트 → 서버 전달용
@RequestHeader String 요청 헤더에서 토큰 직접 추출. 인증 필터에서 사용됨
@AuthenticationPrincipal UserDetails 또는 CustomUserDetails 필터에서 토큰을 검증한 후 생성한 사용자 정보 객체

결론:
@AuthenticationPrincipal은 "JWT 토큰"이 아닌, 토큰으로 인증한 사용자 객체를 받는 것이므로, 참조 자료형(CustomUserDetails 등) 사용하는 게 맞음.


Security Filter Chain을 꼭 거쳐야 할까?

Spring Security의 기본 인증/인가 흐름:

1. HTTP 요청
   ↓
2. 🔐 Security Filter Chain
   ↓
3. 인증(Authentication) → 사용자 정보 확인
   ↓
4. 인가(Authorization) → ROLE 확인
   ↓
5. Controller → @AuthenticationPrincipal 사용 가능

필터를 거쳐야 하는 이유

이유 설명

@PreAuthorize("hasRole('ADMIN')") 작동 조건 SecurityContext에 인증 정보(권한 포함)가 있어야만 작동함
필터에서 UsernamePasswordAuthenticationToken 생성 이 객체에 Role 정보가 담겨 SecurityContext에 저장됨
컨트롤러 이전 단계에서 인가를 걸러냄 인가 실패 시 컨트롤러 진입 자체가 차단됨

필터 없이 @RequestHeader만 사용할 경우

방식 문제점

@RequestHeader("Authorization")으로 직접 토큰 파싱 토큰 검증은 가능하나, Spring Security 권한 처리 불가
hasRole(), @Secured, @PreAuthorize 작동 안 함 SecurityContext에 인증 객체가 없기 때문
확장성, 보안성 떨어짐 커스터마이징 어려워지고 Spring Security 구조와 충돌

결론

Role 기반 인가를 사용하려면 필터에서 반드시 인증 처리 후 SecurityContext에 저장해야 함
→ @AuthenticationPrincipal 사용도 이 흐름에 포함됨.

 

 

 

 

 

 

2. ResponseEntity.ok(user)와 함께 토큰(JWT) 도 자동으로 프론트에 다시 전송되는가?

결론부터 말하자면:

ResponseEntity.ok(user)만으로는 토큰이 다시 전송되지 않음.
✅ 토큰을 다시 응답으로 보내고 싶다면, 명시적으로 응답 헤더나 body에 넣어줘야 함.


이유

JWT는 기본적으로:

  • 로그인할 때 1번만 서버에서 발급해서 클라이언트에게 전달
  • 이후에는 클라이언트가 그 토큰을 저장해서 직접 요청마다 Authorization 헤더로 전송
  • 서버는 보통 토큰을 다시 응답으로 보내지 않음

✅ 예시 비교

❌ 아래처럼 하면 user만 반환됨:

return ResponseEntity.ok(user);
  • 이건 단순히 JSON으로 user 객체만 body에 담김
  • JWT 토큰은 응답에 포함되지 않음

토큰도 같이 보내고 싶다면?

1) 응답 헤더에 담기

return ResponseEntity.ok()
    .header("Authorization", "Bearer " + jwtToken)
    .body(user);

2) 응답 Body에 담기 (예: JSON)

Map<String, Object> response = new HashMap<>();
response.put("user", user);
response.put("token", jwtToken);

return ResponseEntity.ok(response);

이 방식은 로그인 API토큰 갱신 API에서 주로 사용됨.
단순 사용자 정보 조회 API에서는 토큰을 다시 줄 필요가 없음 (이미 클라이언트가 갖고 있음).


정리

조건 설명

Security 필터 통과 ✅ @AuthenticationPrincipal 사용 가능 상태 됨
ResponseEntity.ok(user) ❌ 토큰 자동 포함 ❌ (오직 user 정보만 응답됨)
토큰을 다시 보내려면? ✅ header 또는 body에 직접 넣어야 함
일반적으로 다시 보내야 하나? X, 로그인 외엔 보통 다시 보내지 않음