프로젝트에서 인터셉터를 적용하게 된 계기는 이러하다.
1. 현재 서비스에서 자체 회원가입 기능 없이 OAuth2.0을 통한 소셜 로그인 기능을 제공
2. 소셜 로그인을 통해 로그인 하면 사용자의 username은 OAuth2.0에서 응답 데이터로 제공하는 id를 통해 username을 만들기 때문에 서비스에서 사용할 닉네임으로 사용하기 복잡한(지저분한) 상황
3. 따라서 소셜 로그인에 성공 시 무조건 nickname을 설정하는 페이지로 이동시킬 생각
4. 컨트롤러에 요청하기 전에 인터셉터에서 먼저 접속한 유저가 닉네임이 있는지 없는지 판단하여 없다면 nickname 설정 폼으로 이동시키면 좋을 것 같다고 판단했다.
5. 인터셉터를 도입하기로 결정
HandlerInterceptor
는 DispatcherServlet
에서 컨트롤러를 호출하기 전과 후에 발생하는 이벤트이다.
여기서 나는 컨트롤러를 호출하기 전에 인터셉터를 발생시키고자 하므로 preHandle
메서드를 오버라이드해서 재구성했다.
@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;
}
}
@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/**");
}
}