Notice
Recent Posts
Recent Comments
Link
«   2026/01   »
1 2 3
4 5 6 7 8 9 10
11 12 13 14 15 16 17
18 19 20 21 22 23 24
25 26 27 28 29 30 31
Tags
more
Archives
Today
Total
관리 메뉴

che01 님의 블로그

Spring Boot JWT 인증 & 프로필 관리 트러블슈팅 가이드 본문

카테고리 없음

Spring Boot JWT 인증 & 프로필 관리 트러블슈팅 가이드

che01 2025. 5. 29. 21:15

Spring Boot에서 JWT 인증과 프로필 관리 기능을 구현하면서 마주칠 수 있는 주요 문제점들과 해결 방법을 정리했습니다.

1. @AuthenticationPrincipal JwtPayload 사용 문제 해결

문제 상황

컨트롤러 메서드 매개변수에 JwtPayload jwtPayload를 선언했지만 사용하지 않아서 IDE에서 "사용되지 않는 변수" 경고가 발생하는 경우

해결 방법

@PutMapping("/{id}")
public ResponseEntity<UpdateProfileResponseDto> updateProfile(
    @PathVariable Long id,
    @RequestBody UpdateProfileRequestDto requestDto,
    @AuthenticationPrincipal JwtPayload jwtPayload) {
    
    // 받은 인증 정보를 반드시 사용
    Long userId = jwtPayload.getUserId();
    UpdateProfileResponseDto responseDto = profileService.updateProfile(userId, id, requestDto);
    return ResponseEntity.ok(responseDto);
}

핵심 포인트:

  • 인증 정보를 받았으면 반드시 사용할 것
  • 인증이 필요 없다면 매개변수에서 제거
  • 인증이 필요하다면 서비스 레이어로 전달하여 권한 검증에 활용

2. 프로필 수정 권한 검증 (서비스 레이어)

문제 상황

다른 사용자의 프로필을 수정할 수 있는 보안 취약점

해결 방법

@Transactional
public UpdateProfileResponseDto updateProfile(Long userId, Long profileId, UpdateProfileRequestDto requestDto) {
    Profile profile = profileRepository.findById(profileId)
        .orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND, "프로필을 찾을 수 없습니다."));
    
    // 권한 검증: 요청자와 프로필 소유자가 같은지 확인
    if (!profile.getAccount().getId().equals(userId)) {
        throw new ResponseStatusException(HttpStatus.FORBIDDEN, "수정 권한이 없습니다.");
    }
    
    profile.updateProfile(requestDto.getNickname(), requestDto.getBirth(), requestDto.getBio());
    
    return UpdateProfileResponseDto.from(profile);
}

핵심 포인트:

  • 요청자(userId)와 프로필 소유자(accountId) 일치 여부 검증
  • 권한이 없으면 403 Forbidden 반환
  • 서비스 레이어에서 비즈니스 로직과 권한 검증을 함께 처리

3. 엔티티 updateProfile 메서드 최적화

문제 상황

불필요한 매개변수로 인한 코드 복잡성 증가

해결 방법

@Entity
public class Profile {
    // ... 필드 생략
    
    // 수정이 필요한 필드만 매개변수로 받기
    public void updateProfile(String nickname, Date birth, String bio) {
        this.nickname = nickname;
        this.birth = birth;
        this.bio = bio;
        // Account는 수정하지 않으므로 매개변수에서 제외
    }
}

핵심 포인트:

  • 실제로 수정할 필드만 매개변수로 받기
  • 연관관계 엔티티(Account)는 수정 대상이 아니므로 제외
  • 메서드 시그니처를 간단하고 명확하게 유지

4. 컨트롤러-서비스 메서드 호출 일치성

문제 상황

컨트롤러에서 서비스 메서드 호출 시 매개변수 순서나 타입 불일치

해결 방법

// 서비스 메서드 시그니처
public UpdateProfileResponseDto updateProfile(Long userId, Long profileId, UpdateProfileRequestDto requestDto)

// 컨트롤러 호출 부분
@PutMapping("/{id}")
public ResponseEntity<UpdateProfileResponseDto> updateProfile(
    @PathVariable Long id,
    @RequestBody UpdateProfileRequestDto requestDto,
    @AuthenticationPrincipal JwtPayload jwtPayload) {
    
    Long userId = jwtPayload.getUserId();
    // 서비스 메서드 시그니처와 정확히 일치
    UpdateProfileResponseDto responseDto = profileService.updateProfile(userId, id, requestDto);
    return ResponseEntity.ok(responseDto);
}

핵심 포인트:

  • 메서드 시그니처 일치성 확인
  • 매개변수 순서와 타입 정확히 맞추기
  • IDE의 자동완성 기능 적극 활용

마무리

이런 패턴들을 미리 정리해두면 비슷한 기능을 구현할 때 빠르게 참고할 수 있고, 팀 내에서 일관된 코드 스타일을 유지하는 데도 도움이 됩니다.

특히 인증과 권한 검증은 보안에 직결되는 부분이므로, 위의 체크리스트를 활용해서 빠짐없이 검토하시기 바랍니다!