포스트

메서드에 권한을 붙이다: @PreAuthorize는 어떻게 동작하나

선언적 메서드 시큐리티(@PreAuthorize)의 AOP 프록시 동작과 SpEL 평가, self-invocation 함정을 다룬다.

메서드에 권한을 붙이다: @PreAuthorize는 어떻게 동작하나

URL 패턴만으로는 부족할 때

URL 기반 인가는 “어떤 경로를 누가 호출하는가”는 막지만, 서비스 메서드가 여러 경로·스케줄러·이벤트에서 재사용되면 경로 단위 규칙이 흩어진다. 메서드 시큐리티는 권한 규칙을 그 로직 바로 옆에 선언한다.

동작 — 애너테이션은 AOP 프록시가 가로챈다

@EnableMethodSecurity를 켜면 Spring은 @PreAuthorize가 붙은 빈을 프록시로 감싼다. 호출이 프록시를 지날 때 AuthorizationManager가 SpEL 식을 평가하고, 실패하면 본문 실행 전에 AccessDeniedException을 던진다.

1
2
@PreAuthorize("hasRole('ADMIN') or #order.ownerId == authentication.name")
public void cancel(Order order) { ... }
sequenceDiagram
    Caller->>Proxy: cancel(order)
    Proxy->>AuthorizationManager: evaluate SpEL
    alt 통과
        Proxy->>Target: 실제 메서드 실행
    else 거부
        Proxy-->>Caller: AccessDeniedException
    end

SpEL로 무엇을 검사하나

  • hasRole/hasAuthority — 권한 보유
  • #param — 메서드 인자 참조(위 #order)
  • authentication — 현재 인증 주체
  • @PostAuthorize는 반환값(returnObject)을 검사한다. 단, 이미 실행된 뒤라 부수효과는 되돌릴 수 없다.

운영 함정

  • self-invocation: 같은 클래스 내부에서 this.cancel()로 호출하면 프록시를 거치지 않아 권한 검사가 통째로 건너뛰어진다. 다른 빈을 통해 호출해야 한다.
  • @PostAuthorize의 비용: 대량 컬렉션을 반환한 뒤 거부하면 이미 DB·메모리를 다 쓴 후다. 가능하면 조회 단계에서 소유권을 WHERE로 거른다.

면접 한 줄 Q&A

  • Q. @PreAuthorize가 안 먹는다? → 내부 self-invocation이거나 @EnableMethodSecurity 누락. 프록시를 경유하는지부터 본다.
이 기사는 저작권자의 CC BY 4.0 라이센스를 따릅니다.