지금 게시글 생성 요청을 보면:
{
"title": "제목",
"content": "내용",
"author": "hong"
}
author를 클라이언트가 직접 입력합니다. 문제는:
로그인한 사용자: hong
요청에 보낸 author: "다른사람"
→ 다른 사람인 척 글을 쓸 수 있음
author는 클라이언트가 보내는 게 아니라, JWT 토큰에서 추출해야 합니다. 로그인한 사용자가 누구인지는 서버가 토큰으로 확인합니다.
JWT 필터가 인증에 성공하면 SecurityContextHolder에 Authentication을 저장합니다. 이걸 꺼내는 방법은 다음과 같습니다.
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
String username = auth.getName(); // JWT의 subject (username)
Controller 파라미터에서 바로 꺼낼 수 있습니다:
@PostMapping
public ResponseEntity<...> create(
@AuthenticationPrincipal String username, // JWT의 subject
@RequestBody PostCreateRequest request) {
}
하지만 우리의 JWT 필터에서 principal로 String(username)을 넣었기 때문에, String만 받을 수 있습니다. 더 풍부한 정보가 필요하면 커스텀 객체를 만들 수 있지만, 지금은 username만으로 충분합니다.
여러 곳에서 현재 사용자를 가져와야 하므로, 유틸 클래스를 만듭니다:
package com.myname.board.security;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
public class SecurityUtil {
private SecurityUtil() {} // 인스턴스 생성 방지
// 현재 로그인한 사용자의 username 반환
public static String getCurrentUsername() {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
if (authentication == null || !authentication.isAuthenticated()) {
throw new RuntimeException("인증 정보가 없습니다");
}
return authentication.getName();
}
// 현재 사용자의 역할 확인
public static boolean hasRole(String role) {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
if (authentication == null) {
return false;
}
return authentication.getAuthorities().stream()
.anyMatch(auth -> auth.getAuthority().equals("ROLE_" + role));
}
}
이제 어디서든 SecurityUtil.getCurrentUsername()으로 현재 로그인한 사용자를 가져올 수 있습니다.