본문 바로가기
TIL

[240118] userDetails null 오류

by 진진리 2024. 1. 18.
728x90
프로젝트를 진행하던 중에 게시글 전체를 조회하는 api에서도 UserDetailsImpl을 통해 사용자 정보를 받아올 필요성이 생겼다.
하지만 해당 api에서 가져온 userDetails가 null값인 오류가 발생하였다.

 

UserDetailsImpl을 추가하게 된 BoardController API 코드

// Best 게시글 조회
@GetMapping("/best")
public String getBestBoards(Model model, @AuthenticationPrincipal UserDetailsImpl userDetails) {
    BoardBestListGetRes bestBoards = boardService.getBoardBestList();
    model.addAttribute("bestBoards", bestBoards);
    model.addAttribute("boardList", bestBoards.getBoards());
    log.info("userId : {}", userDetails.getUser().getId());
    return "mainPage";
}

 

처음에 userDetails에서 받아온 값이 null이라는 얘기를 들었을 때 가장 먼저 떠오른 것은 JwtAuthorizationFilter의 whiteList였다.

전에 TIL을 작성했듯이 쿠키에 값을 가지고 있는 경우에도 인가 필터를 통과할 수 있는 api들의 목록을 whiteList로 만들었기 때문이다.

기존에는 권한을 확인하고 않아도 게시글을 조회할 수 있었기 때문에 이 whiteList에도 "/api/boards/best" url도 등록되어 있었다.

 

따라서 해당 url을 주석처리한 한 후에 다시 테스트를 진행하였다.

 

JwtAuthorizationFilter 코드

    private static final List<RequestMatcher> whiteList =
            List.of(
                    new AntPathRequestMatcher("/api/users/signup", HttpMethod.POST.name()),
                    new AntPathRequestMatcher("/api/users/login", HttpMethod.POST.name()),
//                    new AntPathRequestMatcher("/api/boards/best", HttpMethod.GET.name()),
                    new AntPathRequestMatcher("/api/boards/{boardId}", HttpMethod.GET.name()),
                    new AntPathRequestMatcher("/api/boards/region", HttpMethod.GET.name()),
                    new AntPathRequestMatcher("/api/users/naver/callback/**", HttpMethod.GET.name()),
                    new AntPathRequestMatcher("/api/users/kakao/callback/**", HttpMethod.GET.name()),
                    new AntPathRequestMatcher("/**/*.html")
            );

 

이번에는 UserDetails가 null이 아닐 것이라는 예상과 다르게 이번에도 null 값이 나왔다.

그래서 새로 api를 만들어서 userDetails를 잘 받아오는지 테스트를 진행해보았다.

 

"/api/boards"에 해당하는 요청에서는 userDetails를 잘 받아왔는데

"/api/boards/bestone"에서는 userDetails이 null이었다.

"/api/boards/best/one"에서는 userDetails 값을 잘 받아왔다.

 

몇 번의 테스트를 해본 결과 "/api/boards/---" 와 같은 url에 대한 api 요청에서는 모두 userDetails가 null인 것을 알 수 있었다.

그리고 단건 조회에에 해당하는 api 역시 userDetails의 값이 null이었다.

@GetMapping("/{boardId}")
public CommonResponse<BoardGetRes> getBoard(@PathVariable Long boardId, 
    @AuthenticationPrincipal UserDetailsImpl userDetails) {
    log.info("userId : {}", userDetails.getUser().getId());
    return CommonResponse.success(boardService.getBoard(boardId));
}

 

 

그리고 다시 JwtAuthorizationFilter의 whiteList를 보고 혹시나 하는 마음에 주석을 다음과 같이 추가하였다.

    private static final List<RequestMatcher> whiteList =
            List.of(
                    new AntPathRequestMatcher("/api/users/signup", HttpMethod.POST.name()),
                    new AntPathRequestMatcher("/api/users/login", HttpMethod.POST.name()),
//                    new AntPathRequestMatcher("/api/boards/best", HttpMethod.GET.name()),
//                    new AntPathRequestMatcher("/api/boards/{boardId}", HttpMethod.GET.name()),
                    new AntPathRequestMatcher("/api/boards/region", HttpMethod.GET.name()),
                    new AntPathRequestMatcher("/api/users/naver/callback/**", HttpMethod.GET.name()),
                    new AntPathRequestMatcher("/api/users/kakao/callback/**", HttpMethod.GET.name()),
                    new AntPathRequestMatcher("/**/*.html")
            );

 

그러자 "/api/boards/best"에 대한 요청에서 userDetails 값을 제대로 받아오는 것을 확인할 수 있었다.

"/api/boards/{boardId}"에서 boardId에 Long 데이터가 들어가는 경우를 생각해서 whiteList에 추가하였으나 String이 들어가도 같은 api로 인식한다는 것을 알 수 있었다.

 

이번 프로젝트에서는 단건 조회의 경우에도 userDetails를 받아오도록 수정할 예정이기 때문에 둘 다 지우는 것으로 해결 가능했다.

 

그렇다면 {userId}에 Long형 값이 들어가는 경우만 whiteList 처리하기 위해서는 어떻게 해야 할까?

찾아보니 정규표현식을 이용하여 api 요청을 표현할 수 있는 RegexRequestMatcher를 사용할 수 있다고 한다.

이를 가지고 whiteList를 수정한다면 다음과 같이 작성하면 된다.

    private static final List<RequestMatcher> whiteList =
            List.of(
                    new AntPathRequestMatcher("/api/users/signup", HttpMethod.POST.name()),
                    new AntPathRequestMatcher("/api/users/login", HttpMethod.POST.name()),
                    new RegexRequestMatcher("api/boards/(\\d+)", HttpMethod.GET.name()), // 추가한 부분
                    new AntPathRequestMatcher("/api/boards/region", HttpMethod.GET.name()),
                    new AntPathRequestMatcher("/api/users/naver/callback/**", HttpMethod.GET.name()),
                    new AntPathRequestMatcher("/api/users/kakao/callback/**", HttpMethod.GET.name()),
                    new AntPathRequestMatcher("/**/*.html")
            );