카테고리 없음

@AuthenticationPrincipal null 값에 예외 던지기

비뀨_ 2022. 11. 29. 09:54
    //Controller
    @GetMapping
    public ResponseEntity<Page<FishBreadListResDto>> findFishBreadAll(Pageable pageable,
                                                @ModelAttribute SearchCondition searchCondition,
                                                @AuthenticationPrincipal UserPrincipal principal) {
        return ResponseEntity.ok(fishBreadService.findBySearchCondition(principal.getUserId(), pageable, searchCondition));
    }

현재 나는 @AuthenticationPrincipal을 사용해서 유저의 정보를 가져온다.

만약, 유저가 로그인 하지 않은 유저라면  principal의 값에 null이 들어온다.

 

예를들어 물론 로그인안됨에러라는 Custom한 예외를 뿌려줘도 되기도 하고,

if(principal == null) {
	throw new 로그인안됨에러();
}

 

@Secured({"ROLE_USER","ROLE_ADMIN"})

을 Controller쪽 @GetMapping 옆에다가 둬도 되겠지만, 현재 에러 객체를 통일시켜서 반환하기 때문에 가능하면 내가 제어할 수 있는 범위에서는 에러 규격을 맞추고 싶었다.

 

검색을 하는데 @AuthenticationPrincipal이 null이 나온다는 에러만 많고 에러를 던지는 문서는 거의 없는 것 같다.

그러던 중에 커스텀 어노테이션을 만들고 그것을 HandlerMethodArgumentResolver을 상속받는 Class를 만들어서 처리하는 방법을 찾았고

 

참조한 문서는 이거다

꼭 봐서 대충이라도 이해했으면 좋겠다.

왜냐면 난 설명하지 않을거니까!

 

 

일단, 커스텀 어노테이션을 만들자!!

 

티스토리는 코드블록이 너무 안예뻐서 캡쳐함...

나는 AuthUser라는 어노테이션을 사용하여 인증된 사용자만 받을 것이다!

다음은 HandlerMethodArgumentResolver 를 만들자

저 문서를 보면 알겠지만 HandlerMethodArgumentResolver는 일단 너무너무너무너무 많은 클래스들의 부모 인터페이스다.

 

너무 많아....

뭐가 있는지 아는건 중요하지 않고 이 메서드가 뭘 하는 애인가를 알아야한다.

 

boolean supportsParameter(MethodParameter parameter);

@Nullable
Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer,
                NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception;

이 두가지 메서드가 정의된 아주 깔끔한 인터페이스다.

 

supportsParameter는 MethodParameter를 통해서 이걸 지원하냐 안하냐 유무를 따지는거고

만약에 지원한다면 resolveArgument가 실행된다.

 

이제 HandlerMethodArgumentResolver 를 상속받는 클래스를 작성해보자.

 

CustomAuthArgumentResolver라고 이름 지음

먼저 이걸 적용시키기 위해서 supportsParameter 를 간다.

"이거 파라미터로 온 거의 어노테이션이 AuthUser야?" 라고 묻는다. 물론 아니라면 null이 될 것이다.

중요한건 null이 아니면 파라미터로 온 클래스 타입이 UserPrincipal 클래스와 일치하는지 여부를 return 시키고

 

일치한다면 resolveArgument로 넘어간다.

넘어 간 후 SecurityContextHolder에 저장된 인증 객체를 가져 온 후 인증 객체가 있다면 해당 값을 반환하지만

없다면 Custom으로 만든 에러를 보낸다. - 대충 인증되지 않은 사용자라는 뜻

 

자 그럼 만든걸 Spring boot에 적용시켜야 한다.

 

검색하다보니까 Deprecated 된 WebMvcConfigurerAdapter에도 addArgumentResolvers를 추가할 수 있었다.

하지만 난 WebMvcConfigurerAdapter가 아니라 FilterChain 방식으로 해서 오버라이드를 할 수가 없었는데

다행히 HandlerMethodArgumentResolver 는 WebMvcConfigurer ( 영어 너무 길어....!) 안에 있다.

 

WebMvcConfigurer를 상속 받는 클래스를 만들자. 설정 어노테이션도 달자.

위와 같이 Bean으로 등록해준 후  addArgumentResolvers에 추가시켜주면 끝이다.!

 

 

 

위처럼 @AuthUser를 추가로 달아주고 실행해보자.

 

내가 원하는 모양대로 잘 나왔다!!

 

혹시라도 더 좋은 방법이 있으면 꼭 알려주시기 바랍니다.