본문 바로가기
스프링

[인가 설정 리팩토링] Security Config -> @PreAuthorize

by 순원이 2024. 1. 25.

 

문제점:

Path가 추가 될 때마다 시프링 시큐리티에 추가해주어야 한다.

즉, 코드가 길어질 가능성이 있어 가독성이 떨어진다.

또한 컨트롤러에서 어느권한이 접근하는 메소드인지 알 수 없다.

 

방안:

@PreAuthorize 어노테이션 도입

위에서 말한 문제점들을 모두 해결해줄 수 있다!

 

 

리팩토링

  1. config에 @EnableGlobaslMethodSecurity 어노에티션을 안 달아줬다. 적용이 되는 줄 착각했던 것이다
  2. @EnableGlobaslMethodSecurity 를 달아주고 스프링 공식문서를 보니 마이그레이션 됐다
  3. @EnableMethodSecurity로 변경한다

 

 

 

트러블 슈팅

 

test해보니 cusotmeAccessDeniedhandler가 호출이 되어야 하는데 호출이 되고 있지 않는 것을 보고 있다

 

@PreAuthorize("hasRole('ROLE_AUTHUSER')")를 주석처리하고 시큐리티 config에서 롤 제한을 적용해주겠다

보다시피 cusotmeAccessDeniedhandler가 작동 되었다

 

여기서 알 수 있는 것은

똑같은 AccessDeniedException가 일어나지만 예외처리가 다르다는 것이다.

아까 위 스프링 공식문서를 봤을 떄 @PreAuthorize는 AuthorizationManagerBeforeMethodInterceptor가 작동된다

cusotmeAccessDeniedhandler와 AuthorizationManagerBeforeMethodInterceptor의 예외처리 시점이 다르다는 것을 유추해볼 수 있다.

 

해결방법

CustomAccessDeniedHandler 삭제하고

@RestControllerAdvice 이용하기

 

필터를 거치고 인터셉터가 작동되는데 왜 필터단에서 accessDeniException이 발생하지 않았을까? ⇒

인터셉터에서 예외가 핸들링 되지 않아 서버에러로 처리되고 필터로 넘겨집니다. 필터에서 검사하는 CustomAccessDeniedHandler는  서버 에러가 AccessDeniedException인지 알 수가 없어  그대로  AccessDeniedException가 처리되지 않고 서버 에러로 처리되었던 것입니다.

일반적으로 CustomAccessDeniedHandlerAccessDeniedException을 처리하기 위해 정의되며, 이는 @PreAuthorize로부터 발생할 수도 있습니다. 그러나 @PreAuthorize와 같은 메서드 수준의 보안 어노테이션은 서블릿 필터 체인(필터)에서 동작하는 것이 아니라, AOP를 기반으로 동작합니다. 그 결과, @PreAuthorize에 의한 보안 검사는 서블릿 필터 체인이 수행된 이후에 이루어집니다. 검사 시점이 다른 겁니다.

Spring Security 프로젝트는 스프링 관련 프로젝트들은 활용하지만 웹 의존성(Spring MVC)은 사용하지 않습니다. 시큐리티 앞에 스프링이 붙어서 Spring Context 안에서 동작하는 디스패처 서블릿 혹은 인터셉터 아닌가? 라고 오해할 수 있지만 Fliter(서블릿 컨테이너의 영역)에 해당합니다.