[프로젝트] 스프링부트 인터셉터 적용기

큰모래·2023년 6월 5일
0

개요


프로젝트에서 인터셉터를 적용하게 된 계기는 이러하다.
1. 현재 서비스에서 자체 회원가입 기능 없이 OAuth2.0을 통한 소셜 로그인 기능을 제공
2. 소셜 로그인을 통해 로그인 하면 사용자의 username은 OAuth2.0에서 응답 데이터로 제공하는 id를 통해 username을 만들기 때문에 서비스에서 사용할 닉네임으로 사용하기 복잡한(지저분한) 상황
3. 따라서 소셜 로그인에 성공 시 무조건 nickname을 설정하는 페이지로 이동시킬 생각
4. 컨트롤러에 요청하기 전에 인터셉터에서 먼저 접속한 유저가 닉네임이 있는지 없는지 판단하여 없다면 nickname 설정 폼으로 이동시키면 좋을 것 같다고 판단했다.
5. 인터셉터를 도입하기로 결정



HandlerInterceptor


HandlerInterceptorDispatcherServlet에서 컨트롤러를 호출하기 전과 후에 발생하는 이벤트이다.

  • preHandle
    • 컨트롤러를 호출하기 전에 발생하는 메서드
    • true를 반환하면 요청한 컨트롤러를 호출, false를 반환하면 컨트롤러를 호출하지 않는다.
  • postHandle
    • 컨트롤러가 실행 후 View가 렌더링되기 전에 실행된다.
  • afterCompletion
    • 컨트롤러가 실행되고 View가 랜더링 된 후에 실행된다.

여기서 나는 컨트롤러를 호출하기 전에 인터셉터를 발생시키고자 하므로 preHandle 메서드를 오버라이드해서 재구성했다.



HandlerInterceptor 구현


  • SecurityContextHolder를 통해 접속한 유저의 authentication 객체를 받는다.
  • authentication이 null이라면 아직 로그인하지 않은 회원이므로 로그인 페이지로 이동시키고 false를 반환해서 요청한 컨트롤러를 호출시키지 않는다.
  • 인증된 사용자 객체가 User 클래스의 인스턴스라면 해당 정보를 통해 username을 얻고 username을 통해 Member 객체를 얻을 수 있다.
  • 만약 Member 객체가 null이라면 역시 로그인이 되지 않은 상태이니 로그인 페이지로 이동
  • 이 다음으로 이제 닉네임이 null이라면 닉네임 설정 페이지로 이동
  • 인증된 사용자이며 닉네임이 있다면 true를 반환해서 원래 요구한 컨트롤러 호출
  • 위의 모든 조건들에 안걸렸다면 역시 인증되지 않은 회원이므로 로그인폼으로 이동
@Component
@RequiredArgsConstructor
public class NicknameCheckInterceptor implements HandlerInterceptor {

    private final MemberService memberService;

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();

        if (authentication == null) {
            response.sendRedirect("/user/member/login");
            return false;
        }


        if (authentication.getPrincipal() instanceof User) {
            User user = (User)authentication.getPrincipal();
            String username = user.getUsername();
            Member member = memberService.findByUsername(username).orElse(null);

            if (member == null) {
                response.sendRedirect("/user/member/login");
                return false;
            }

            if (member.getNickname() == null) {
                response.sendRedirect("/user/member/update/nickname");
                return false;
            }

            return true;
        }

        response.sendRedirect("/user/member/login");
        return false;
    }

}


HandlerInterceptor 등록


  • 위에서 구현한 HandlerInterceptor를 적용하려면 Config 파일을 만들어야 한다.
  • WebMvcConfigurer를 implements해서 addInterceptors 메서드를 오버라이드 한다.
  • registry에 구현한 인터셉터를 등록하고 적용할 패턴 그리고 인터셉터 기능을 제외할 패턴을 등록한다.
@Configuration
@RequiredArgsConstructor
public class WebConfig implements WebMvcConfigurer {

    private final NicknameCheckInterceptor nicknameCheckInterceptor;

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(nicknameCheckInterceptor)
                .addPathPatterns("/**")
                .excludePathPatterns("/user/member/login", "/css/**", "/resource/**", "/starboot/**", 
                "/vendor/**", "/user/member/update/nickname", 
                "/user/layout/**", "/common/**");
    }
}
profile
큰모래

0개의 댓글