Notice
Recent Posts
Recent Comments
Link
| 일 | 월 | 화 | 수 | 목 | 금 | 토 |
|---|---|---|---|---|---|---|
| 1 | 2 | 3 | 4 | 5 | 6 | |
| 7 | 8 | 9 | 10 | 11 | 12 | 13 |
| 14 | 15 | 16 | 17 | 18 | 19 | 20 |
| 21 | 22 | 23 | 24 | 25 | 26 | 27 |
| 28 | 29 | 30 |
Tags
- 이것이 자바다
- 윤성우 열혈자료구조
- s
- C 언어 코딩 도장
- stream
- JSON
- Serialization
- 알기쉬운 알고리즘
- coding test
- Stack
- 이스케이프 문자
- C programming
- ㅅ
- buffer
- Algorithm
- Selection Sorting
- list 컬렉션
- 메모리구조
- Graph
- R
- datastructure
- 혼자 공부하는 C언어
- insertion sort
- 윤성우의 열혈 자료구조
Archives
- Today
- Total
Engineering Note
[Spring] OncePerRequestFilter 본문
OncePerRequestFilter
- Spring Framework에서 제공하는 클래스로, 하나의 요청당 딱 한 번만 실행하게 하는 필터
웹 어플리케이션은 서블릿이 요청을 받아 처리할 때 다른 서블릿으로 요청을 Forwad하거나 리다이렉트 하는 등의 작업이 일어나는데, 이때Filter 인터페이스만 사용하면 서블릿 컨테이너(Tomcat 등)의 설정에 따라 필터가 중복해서 실행될 수 있는데 이를 방지하기 위해 사용합니다.
OncePerRequestFilter가 필요한 이유(배경)
- 문제점 : 인증(Authentication)이나 로깅(loggin) 요청처럼 한 번만 수행되어야 하는 작업이 중복 실행되어서 자원을 낭비하거나 로직의 오류가 발생할 수 있습니다.
- 해결책 : OncePerRequestFilter를 상속받으면, 해당요청이 이 필터를 거쳤는지 확인하는 로직이 내장되어 있어 자동으로 중복 실행을 차단해줍니다.
주요 특징
- 동일 요청 내 1회 실행 보장: doFilterInternal 메서드만 구현하면 됩니다.
- Spring Security와의 궁합: JWT 토큰 인증처럼 요청마다 사용자 정보를 확인해야 하는 필터를 만들 때 표준처럼 사용됩니다.
- 유연한 제어: 특정 조건(URL 패턴)에 따라 필터를 거치지 않게 설정할 수 있는 shodnotFilter 메서드를 제공합니다.
JWT 토큰 인증 코드를 구현한 예시 코드
package com.shop.core.security;
import com.shop.common.constant.Role;
import com.shop.domain.member.Member;
import com.shop.domain.member.MemberRepository;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.filter.OncePerRequestFilter;
import java.io.IOException;
import java.util.List;
/**
* JWT 인증 필터
* 모든 HTTP 요청에서 JWT 토큰을 검증하고 인증 정보를 SecurityContext에 저장
*/
@Slf4j
@Component
@RequiredArgsConstructor
public class JwtAuthenticationFilter extends OncePerRequestFilter {
private final JwtTokenProvider jwtTokenProvider;
private final MemberRepository memberRepository;
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
try {
// 1. Request Header에서 JWT 토큰 추출
log.info("Request Header Authorization: {}", request.getHeader("Authorization"));
String token = extractTokenFromRequest(request);
// 2. 토큰이 있고, 유효하면 인증정보 설정
if(token != null && jwtTokenProvider.validateToken(token)) {
// 토큰에서 memberId 추출
Long memberId = jwtTokenProvider.getMemberId(token);
String email = jwtTokenProvider.getEmail(token);
Member member = memberRepository.findByEmail(email).orElseThrow(() -> new UsernameNotFoundException(email));
//회원 권한 설정
UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(memberId, null, List.of(new SimpleGrantedAuthority("ROLE_" + member.getRole().USER.name())));
//Security 인증정보 저장
SecurityContextHolder.getContext().setAuthentication(authentication);
log.debug("JWT 인증 성공: memberId = {}, email = {} ", memberId, email);
}
} catch (Exception e) {
throw new RuntimeException(e);
}
//다음 필터로 진행
filterChain.doFilter(request, response);
}
/**
* Request Header에서 Bearer Token 추출
*/
private String extractTokenFromRequest(HttpServletRequest request) {
String bearerToken = request.getHeader("Authorization");
if(StringUtils.hasText(bearerToken) && bearerToken.startsWith("Bearer ")) {
return bearerToken.substring(7);//"Bearer " 제거
}
return null;
}
}
'Server' 카테고리의 다른 글
| [Server] Redis 자료구조 (1) | 2025.12.27 |
|---|---|
| [Server] GCP 인스턴스 만들고 배포하기 + githubaction(무료 크레딧 사용) (0) | 2025.12.21 |
| [Server] Access Token과 Refresh Token을 사용하는 이유 (0) | 2025.12.19 |
| [JPA] em.flush(); (0) | 2025.12.15 |
| [Spring] Spring Security 적용하고 테스트 하기 (0) | 2025.12.10 |
Comments