본문으로 건너뛰기
Advertisement

12.5 객체 수준 보안(@PreAuthorize) 매서드 시큐리티

SecurityFilterChain 내부에 설정하는 requestMatchers("/api/admin/**").hasRole("ADMIN") 방식은 웹 URL(엔드포인트) 수준의 거시적인 라우팅 방어벽입니다. 하지만 조금 더 세밀하게 **"특정 비즈니스 메서드 자체를 호출할 때 파라미터나 상태를 감시"**하고 싶을 때는 메서드 시큐리티(Method Security)를 사용합니다.

1. @EnableMethodSecurity 활성화

Spring Security 6 (Boot 3.x)부터는 기존 @EnableGlobalMethodSecurity 대신 **@EnableMethodSecurity**를 사용합니다.

@Configuration
@EnableWebSecurity
@EnableMethodSecurity // 이 애너테이션 하나로 @PreAuthorize, @Secured 등이 활성화됩니다.
public class SecurityConfig {
// ...
}

2. @PreAuthorize와 @PostAuthorize 실전 문법

가장 강력하고 유연한 (SpEL - Spring Expression Language) 기반의 보안 애너테이션입니다. 메서드가 실행되기 직전에 파라미터를 검사(@PreAuthorize)하거나, 실행된 직후 반환값을 검사(@PostAuthorize)할 수 있습니다.

@Service
@RequiredArgsConstructor
public class BoardService {

// 1. 단순 권한 검사 (ADMIN 역할만 호출 가능)
@PreAuthorize("hasRole('ADMIN')")
public void deleteNotice(Long boardId) { ... }

// 2. 파라미터와 로그인 유저(Principal) 비교 (자신이 쓴 글만 조회 가능)
@PreAuthorize("#userId == authentication.principal.id or hasRole('ADMIN')")
public BoardDto getPrivatePost(Long boardId, Long userId) { ... }

// 3. 반환된 결과값을 검사 (PostAuthorize - 메서드는 실행되지만, return 객체를 까보고 권한이 맞아야 결과 전달)
@PostAuthorize("returnObject.ownerId == authentication.principal.id")
public CustomDocument fetchSecretDocument(Long docId) {
return documentRepository.find(docId); // 이미 쿼리는 날아갔음!
}
}

3. 커스텀 권한 판단 Bean 연동

권한 인가 로직이 매우 복잡하여 SpEL 한 줄로 정리하기 힘들 때는 커스텀 스프링 빈(Bean)을 호출할 수 있습니다. 이 방식이 실무에서 엄청난 유연성을 제공합니다.

@Component("boardSecurity")
public class BoardSecurityEvaluator {
public boolean isOwner(Long boardId, CustomUserDetails user) {
// 복잡한 DB 조회 및 로직 비교 후 true/false 리턴
return boardRepository.checkOwnerShip(boardId, user.getId());
}
}

사용처:

// @보안빈이름.메서드(파라미터 변수명, 내재된 authentication.principal(유저객체))
@PreAuthorize("@boardSecurity.isOwner(#boardId, principal)")
public void updatePost(Long boardId, PostUpdateDto dto) {
// ...게시글 수정 수행
}

이로써 지저분한 if (user.getId() != board.getOwnerId()) throw Exception(); 비즈니스 코드를 핵심 로직 안에서 완전히 덜어내는 완벽한 AOP 분리가 가능합니다.

Advertisement