JWT 인증 필터를 왜 @Component로 등록하면 안 되는가?
- JWT 인증 필터는 @Component로 빈 등록을 하면 Spring Security의 필터 체인에 제대로 결합되지 않아
의도한 대로 동작하지 않을 수 있습니다.필터 체인에서의 순서가 엉킬 수 있기 때문입니다.
Spring Security의 필터 체인 내에서 필터를 등록하려면,
@Component로 등록하는 대신 SecurityConfig에서 명시적으로 등록해야 합니다.
@Component로 필터를 등록하게 되면, Spring이 이 필터를 자동으로 FilterChain에 추가하게 되는데,
이 방식은 Spring Security 필터 체인과 충돌할 수 있습니다.
Spring Security는 보안 필터 체인을 구성하는 순서가 매우 중요하며,
@Component로 등록된 필터가 Spring Security 필터 체인 안에서 예상치 못한 순서로 동작할 수 있습니다.
이로 인해 JWT 필터가 인증 과정 전에 실행되지 않거나 인증 후에도 실행되지 않는 등의 문제가 발생할 수 있습니다.
올바른 방법:
SecurityConfig에서 필터 등록
JWT 필터는 SecurityConfig 클래스에서 Spring Security의 필터 체인에 명시적으로 등록해야 합니다.
이렇게 하면 필터 체인 순서를 제어할 수 있습니다.
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
private final JwtAuthenticationFilter jwtAuthenticationFilter;
public SecurityConfig(JwtAuthenticationFilter jwtAuthenticationFilter) {
this.jwtAuthenticationFilter = jwtAuthenticationFilter;
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().disable() // CSRF 비활성화 (JWT 토큰 사용시 일반적으로 비활성화)
.authorizeRequests()
.antMatchers("/login", "/signup").permitAll() // 로그인, 회원가입은 누구나 접근 가능
.anyRequest().authenticated() // 그 외 모든 요청은 인증 필요
.and()
.addFilterBefore(jwtAuthenticationFilter, UsernamePasswordAuthenticationFilter.class); // JWT 필터를 `UsernamePasswordAuthenticationFilter` 전에 추가
}
}
JWT 인증 필터 구현
필터를 SecurityConfig에 등록한 후, JWT 필터는 OncePerRequestFilter를 확장하여 작성할 수 있습니다.
이렇게 하면 HTTP 요청이 들어올 때마다 JWT를 추출하고 유효성 검사를 할 수 있습니다.
public class JwtAuthenticationFilter extends OncePerRequestFilter {
private final JwtTokenProvider jwtTokenProvider;
public JwtAuthenticationFilter(JwtTokenProvider jwtTokenProvider) {
this.jwtTokenProvider = jwtTokenProvider;
}
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
// JWT 토큰 추출
String token = jwtTokenProvider.resolveToken(request);
if (token != null && jwtTokenProvider.validateToken(token)) {
Authentication authentication = jwtTokenProvider.getAuthentication(token); // 인증 정보 생성
SecurityContextHolder.getContext().setAuthentication(authentication); // 인증 정보 설정
}
filterChain.doFilter(request, response); // 필터 체인 계속 실행
}
}
JwtTokenProvider 클래스 예
이 클래스는 JWT 토큰을 처리하는 다양한 메서드를 제공합니다.
예를 들어, 토큰을 생성하거나, 유효성을 검사하고, 인증 객체를 만드는 메서드를 구현합니다.
@Component
public class JwtTokenProvider {
private final String secretKey = "mySecretKey"; // JWT 비밀 키 (보안 목적상 외부에서 관리하는 것이 좋음)
// 토큰을 요청에서 추출하는 메서드
public String resolveToken(HttpServletRequest request) {
String bearerToken = request.getHeader("Authorization");
if (bearerToken != null && bearerToken.startsWith("Bearer ")) {
return bearerToken.substring(7); // "Bearer " 뒤의 JWT 부분 추출
}
return null;
}
// 토큰 유효성 검증
public boolean validateToken(String token) {
try {
// JWT 토큰이 유효한지 체크하는 로직 (만료 검사 등)
return true; // 여기에 토큰 검증 로직 추가
} catch (Exception e) {
return false;
}
}
// JWT 토큰을 기반으로 Authentication 객체를 생성하는 메서드
public Authentication getAuthentication(String token) {
// 토큰을 통해 사용자의 정보를 가져오고, 이를 기반으로 Authentication 객체 생성
UserDetails userDetails = new User("username", "password", new ArrayList<>());
return new UsernamePasswordAuthenticationToken(userDetails, "", userDetails.getAuthorities());
}
}
정리
- 필터를 @Component로 자동 등록하는 것은 Spring Security 필터 체인과 충돌할 수 있습니다.
- 필터를 명시적으로 등록하려면 SecurityConfig에서 addFilterBefore() 메서드를
사용하여 필터 순서를 지정해야 합니다. - JWT 필터는 요청을 가로채어 인증을 처리하고, 이후의 필터 체인을 정상적으로 흐르도록 해야 하므로,
필터 순서가 매우 중요합니다
'Spring' 카테고리의 다른 글
[Spring] 스프링 @Schduled 사용법, 개념 및 구현해보자 (0) | 2024.06.14 |
---|---|
[Spring] 스프링에서 네트워크 Ping 테스트 (0) | 2024.06.14 |
[Spring] Spring Quartz, Spring Batch, @Scheduled 개념 (0) | 2024.06.13 |
[Spring] WebFlux란 ?? (0) | 2024.03.21 |
[Spring] dependencyManagement 와 dependencies의 차이점 (0) | 2024.02.27 |