: 컨트롤러로 들어오는 HTTPRequest와 컨트롤러가 응답하는 HTTPResponse를 가로채는 역할을 한다.
특정 권한이 필요한 페이지 요청 시 권한이 있는지를 확인하거나, 세션이 만료되었는지 확인하는 등의 용도로 사용한다.
여러 페이지에서 로그인이 되었는지 확인해야 하는 것처럼 다수의 컨트롤러에 대해 동일한 기능을 적용해야 할 때 사용한다.
실행 위치
역할
Filter
인터셉터
AOP
스프링에서는 세 가지 시점에 인터셉터 처리가 가능하다.
컨트롤러 실행 전
컨트롤러 실행 후, 아직 뷰를 실행하기 전
뷰를 실행한 이후
HandlerInterceptor를 구현한 클래스를 정의한다.
→ @Component : preHandle(), postHandle(), afterCompletion()
WebMvcConfigurer 인터페이스를 구현한 클래스를 정의하고 1번에서 만든 클래스를 등록해줘야 한다.
→ @Configuration : addInterceptors()
@GetMapping("/login")
public String loginForm(Model model) {
model.addAttribute("loginForm", new LoginForm());
return "login";
}
@PostMapping("/login")
public String login(@ModelAttribute("loginForm") LoginForm form, BindingResult bindingResult, HttpServletResponse response) {
User loginUser = service.login(form.getLoginId(), form.getPassword());
log.info("login? {}", loginUser);
if (loginUser == null) {
bindingResult.reject("loginFail", "아이디 또는 비밀번호가 맞지 않습니다.");
}
if (bindingResult.hasErrors()) {
return "login";
}
Cookie cookie = new Cookie("idx", String.valueOf(loginUser.getIdx()));
cookie.setMaxAge(60 * 60); // 쿠키 유효 시간 : 1시간
response.addCookie(cookie);
// 로그인 성공 처리
return "redirect:/main";
}
@GetMapping("/user/main")
public String userList(Model model) {
List<User> users = service.getAllUsers();
model.addAttribute("users", users);
return "user/main";
}
@GetMapping("/user/info/{userId}")
public String userInfo(@PathVariable String userId, Model model) {
log.info("Fetching user info for userId: {}", userId);
User user = service.getLoginUser(userId);
if (user == null) {
log.warn("User not found for userId: {}", userId);
return "redirect:/login";
}
log.info("User found: {}", user);
model.addAttribute("user", user);
return "user/info";
}
로그인을 한 사용자만 글을 열람할 수 있도록 권한이 없는 사용자 접근 시 Interceptor가 요청을 빼앗아 /login페이지로 리다이렉트한다.
package org.study.board.config;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
@Component
public class AuthInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(final HttpServletRequest request, final HttpServletResponse response,Object handler) throws Exception {
HttpSession session = request.getSession();
// 사용자가 로그인을 하면 세션 메모리 영역에 user 키-값 구조로 저장 처리할 예정
Object user=session.getAttribute("user");
System.out.println(user);
System.out.println("preHandler 동작 확인");
if(user==null){
response.sendRedirect("/login");
return false;
}
return true;
}
}
preHandle()
메서드는 false 리턴 시 다음 컨트롤러를 실행하지 않는다.
postHandle()
메서드는 컨트롤러 익셉션 발생 시 실행하지 않는다.
afterCompletion()
메서드는 뷰가 클라이언트에 응답을 전송한 뒤에 실행된다. 컨트롤러에서 익셉션 발생 시 ex 파라미터에 전달되고, 발생하지 않으면 null이 전달된다. 컨트롤러 실행 후 로그를 남기거나, 실행 시 간을 기록하는 등의 후처리를 하기 위한 메서드이다.
package org.study.board.config;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.util.Arrays;
import java.util.Optional;
@Component
public class AuthInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(final HttpServletRequest request, final HttpServletResponse response,Object handler) throws Exception {
// Cookie 방식
// 쿠키에서 사용자 토큰을 찾습니다.
Optional<Cookie> userTokenCookie = Arrays.stream(request.getCookies())
.filter(cookie -> cookie.getName().equals("idx"))
.findFirst();
// 사용자 토큰이 존재하지 않으면 로그인 페이지로 리다이렉트합니다.
if (!userTokenCookie.isPresent()) {
response.sendRedirect("/login");
return false;
}
// 토큰이 존재하면 인증을 성공한 것으로 간주합니다.
return true;
}
}
package org.study.board.config;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
@Autowired
private AuthInterceptor sessionInterceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {
// 명시하는 요청 설계 주소에서만 동작하도록
// localhost:8080/hello <-- 동작x
// localhost:8080/user/info/{userId} <-- 인터셉터 동작
registry.addInterceptor(sessionInterceptor)
.addPathPatterns("/board/**"); // board 아래에 있는것만 가로챔
}
}
WebMvcConfigurer
의 addInterceptors()
메서드로 인터셉터 설정InterceptorRegister
객체의 addInterceptor()
메서드로 등록한 인터셉터를 설정InterceptorRegister
객체의 addPathPatterns("ant 패턴")
으로 인터셉트할 url 설정참고자료
https://spyair.tistory.com/161
https://velog.io/@fortice/Spring-세션-인터셉터-쿠키