세션과 필터를 사용해 사용자의 정보를 이용해보자
Filter
: HTTP 요청/응답 흐름을 가로채서 전처리 및 후처리를 할 수 있는 기능. 로그인 인증과 같은 cross-cutting concern(횡단 관심사)에 적합.
HttpSession
: 서버와 클라이언트 간의 상태 유지를 위한 객체. 로그인 상태 유지에 사용됨.
@Configuration
: 스프링 설정 클래스임을 명시. Bean 등록에 사용됨.
@Bean
: 개발자가 직접 제어하는 객체를 스프링 컨테이너에 등록할 때 사용.
로그인 시 세션 생성 → loginUser 저장
필터에서 요청 URI 확인
WHITE_LIST는 통과
그 외는 세션 존재 여부 확인
로그아웃 시 세션 제거 invalidate()
1. 세션 생성
클라이언트가 로그인 요청을 보낼 때, request.getSession()을 통해 세션 생성
→ 고유한 세션 ID (JSESSIONID) 생성, 클라이언트에게 쿠키 형태로 전달
2. 세션 유지
클라이언트는 이후 모든 요청마다 JSESSIONID 쿠키를 함께 보냅니다.
→ 서버는 이 쿠키를 읽고, 해당 ID에 매핑된 세션을 조회합니다.
3. 세션 저장소
서버 메모리 또는 Redis 같은 외부 저장소에 세션이 저장됨!
→ 세션 내부에는 Map<String, Object> 형태로 사용자 데이터를 저장
Spring Boot에서 Filter와 HttpSession을 사용하여 로그인 인증 처리를 구현했습니다. @Configuration을 이용해 필터를 등록하고, 세션을 활용해 로그인 상태를 유지하며, 로그아웃 시 세션을 무효화하는 구조로 구성되었다.
@Slf4j // Lombok - log를 위한 어노테이션
public class LoginFilter implements Filter {
private static final String[] WHITE_LIST = {"/news/signup", "/news/login"};
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain)
throws IOException, ServletException {
HttpServletRequest httpRequest = (HttpServletRequest) servletRequest;
String requestURI = httpRequest.getRequestURI();
log.info("로그인 필터 로직 실행");
if (!isWhiteList(requestURI)) {
HttpSession session = httpRequest.getSession(false);
if (session == null || session.getAttribute("loginUser") == null) {
throw new NotActiveException("로그인 해주세요");
}
}
filterChain.doFilter(servletRequest, servletResponse);
log.info("로그인 인증 성공");
}
private boolean isWhiteList(String requestURI) {
for (String s : WHITE_LIST) {
if (requestURI.startsWith(s)) {
return true;
}
}
return false;
}
}
WHITE_LIST를 정의하여, 로그인 없이(세션 값 없이) 접근 가능한 URI를 사전에 정의함
doFilter() - 요청이 들어오면 실행되는 메서드.
→ WHITE_LIST 이외의 요청의 경우 세션 검사
getSession(false)
세션 가져오는 get이 기본적으로 true로 설정되어있는데, 이를 false로 설정하여 세션이 없을 경우 새로 생성하지 않고 null을 반환
@Configuration // 설정 클래스임을 명시
public class WebConfig {
@Bean
public FilterRegistrationBean<Filter> loginFilter() {
FilterRegistrationBean<Filter> filterRegistrationBean = new FilterRegistrationBean<>();
filterRegistrationBean.setFilter(new LoginFilter()); // 필터 등록
filterRegistrationBean.setOrder(1); // 필터 실행 순서
filterRegistrationBean.addUrlPatterns("/*"); // 전체 URL에 필터 적용
return filterRegistrationBean;
}
}
@COnfiguration 어노테이션을 통해 Spring에게 이거 설정하는 클래스다!!!! 라고 명시해주자
그리고 @Bean 등록을 해주고
아까 만들어둔 LoginFilter 클래스를 필터로 등록하자
setOrder()를 통해 필터의 우선순위도 정해주면된다.
HttpSession session = request.getSession(); // 기존 세션이 없으면 생성
session.setAttribute("loginUser", user); // 로그인 사용자 정보 저장
getSession()- 세션이 존재하지 않으면 새로 생성
setAttribute()- 세션에 로그인 사용자 정보를 저장 → 이후 인증에 활용
HttpSession session = request.getSession(false);
if (session != null) {
session.invalidate(); // 세션 무효화
return ResponseEntity.status(SuccessCode.LOGOUT_SUCCESS.getHttpStatus())
.body(CommonResponse.of(SuccessCode.LOGOUT_SUCCESS, "success"));
} else {
throw new ResponseStatusException(HttpStatus.BAD_REQUEST);
}
getSession(false) - 세션이 없으면 null을 반환
invalidate() - 서버 메모리에서 세션을 제거
application.properties에서 설정
server.servlet.session.timeout=30m
30m → 30분 동안 요청이 없으면 세션 만료!
로그인 시도 시도마다 실패 카운트를 세션이나 메모리에 저장
→ 5회 이상 실패하면 접근 제한하기!
public void loginFail(HttpSession session) {
Integer failCount = (Integer) session.getAttribute("loginFailCount");
if (failCount == null) {
failCount = 0;
}
failCount++;
session.setAttribute("loginFailCount", failCount);
}
세션값을 받고, 만약 로그인 틀렸을때 failCount가 올라갈 수 있도록 설정
public void loginBlock(HttpSession session) {
Integer failCount = (Integer) session.getAttribute("loginFailCount");
if (failCount >5) {
throw new ResponseStatusException(HttpStatus.BAD_REQUEST);
}
}
그리고 loginBlock 메서드를 생성해,
만약 실패 횟수가 5회가 넘으면 실패를 반환할 수 있도록 설정!