스프링 시큐리티 6.2 버전 이후로 apply() 메서드를 이용한 JwtAuthenticationFilter 가 등록이 안됩니다.
직접 만든 JwtAuthenticationFilter 를 스프링 시큐리티 필터로 등록하는 과정에서 HttpSecurity.apply() 메서드를 활용하셨는데
현 시점 스프링 시큐리티 6.2 버전 이후로는 apply() 메서드가 deprecated 되어 더 이상 지원되지 않는 상황입니다.
이걸 6.2 버전에 맞게 대체할 방법을 찾다보니 with() 메서드를 사용하면 되는것까지는 확인했는데 이 메서드는 또 어떻게 써야할지 모르겠습니다.
public <C extends SecurityConfigurerAdapter<O,B>> B with(C configurer, Customizer<C> customizer) throws Exception
어떻게 하면 강의에서처럼 JwtAuthenticationFilter 를 스프링 시큐리티 필터로 등록해줄 수 있을까요
위의 캡처본을 보시면 알 수 있듯이 apply() 메서드는 현재 제가 사용중인 스프링 시큐리티 6.2 버전 부터는 deprecated 되어 지원이 되고 있지 않은 상황이라 필터 등록이 되지 않고있습니다.
Answer 1
0
작성자 본인입니다. 일단 해결은 했습니다.
스프링 시큐리티 문서 뒤지면서 with 메서드로 커스텀 필터 어떻게 적용시키는지 찾아보다가 발견했습니다.
https://docs.spring.io/spring-security/reference/servlet/configuration/java.html#jc-custom-dsls
여기서 보니까 with 메서드에 두번째 매개변수로 Customizer<T> customizer 넘겨주는 부분에서 람다식을 작성해서 메서드 참조로 넘겨버리더군요
문서에서는 커스텀 필터 내부에 작성해둔 flag(true) 메서드를 넘겨주는식으로 작성되어 있었는데
이 강의에서 실습으로 만든 내부 클래스 CustomSecurityFilterManager 에는 configure 메서드를 오버라이드 해온거 말곤 다른 메서드는 없었기에 그냥 대충 getClass() 같은 Object 클래스 단의 메서드 참조를 넘기면 될 까 싶더니 정상적으로 잘 실행이 되더라구요
(참고로 toString() 메서드를 참조로 보내도 정상적으로 잘 동작했습니다. 도대체 왜 그런건지는 모르겠습니다만.....)
원래는 이렇게 작성하는게 아나라 스프링 시큐리티 문서에서 처럼 내부에 작성되어 있는 메서드 같은걸 참조로 보내줘야 할 것같은데, 일단 해결되기는 했으니까 이대로 계속 강의 들어보겠습니다.
아래는 해결 코드입니다.
// JWT 필터 등록
http.with(new CustomSecurityFilterManager(), customizer -> customizer.getClass());
1

with 를 통해 this를 리턴하면서, 빌더 패턴으로 코드를 작성하고자 할 때 편리합니다.
저희 예제는 공부를 부분적으로 하려고 빌더 패턴을 이용하지 않았습니다.

apply가 this를 리턴하지 않아서, with 메서드는 this를 리턴하게 됩니다. 그래서 코드를 저는 아래와 같이 변경하였습니다.
package shop.mtcoding.bank.config;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpStatus;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.CorsConfigurationSource;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import shop.mtcoding.bank.config.jwt.JwtAuthenticationFilter;
import shop.mtcoding.bank.config.jwt.JwtAuthorizationFilter;
import shop.mtcoding.bank.domain.user.UserEnum;
import shop.mtcoding.bank.util.CustomResponseUtil;
@Configuration
public class SecurityConfig {
private final Logger log = LoggerFactory.getLogger(getClass());
@Bean // Ioc 컨테이너에 BCryptPasswordEncoder() 객체가 등록됨.
public BCryptPasswordEncoder passwordEncoder() {
log.debug("디버그 : BCryptPasswordEncoder 빈 등록됨");
return new BCryptPasswordEncoder();
}
// JWT 필터 등록이 필요함
public class CustomSecurityFilterManager extends AbstractHttpConfigurer<CustomSecurityFilterManager, HttpSecurity> {
@Override
public void configure(HttpSecurity builder) throws Exception {
AuthenticationManager authenticationManager = builder.getSharedObject(AuthenticationManager.class);
builder.addFilter(new JwtAuthenticationFilter(authenticationManager));
builder.addFilter(new JwtAuthorizationFilter(authenticationManager));
super.configure(builder);
}
public HttpSecurity build(){
return getBuilder();
}
}
// JWT 서버를 만들 예정!! Session 사용안함.
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
log.debug("디버그 : filterChain 빈 등록됨");
http.headers(h -> h.frameOptions(f -> f.sameOrigin()));
http.csrf(cf->cf.disable());
http.cors(co->co.configurationSource(configurationSource()));
http.sessionManagement(sm->sm.sessionCreationPolicy(SessionCreationPolicy.STATELESS));
http.formLogin(f->f.disable());
http.httpBasic(hb->hb.disable());
http.with(new CustomSecurityFilterManager(), c-> c.build());
// 인증 실패
http.exceptionHandling(e-> e.authenticationEntryPoint((request, response, authException) -> {
CustomResponseUtil.fail(response, "로그인을 진행해 주세요", HttpStatus.UNAUTHORIZED);
}));
http.exceptionHandling(e-> e.accessDeniedHandler((request, response, accessDeniedException) -> {
CustomResponseUtil.fail(response, "권한이 없습니다", HttpStatus.FORBIDDEN);
}));
http.authorizeHttpRequests(c->
c.requestMatchers("/api/s/**").authenticated()
.requestMatchers("/api/admin/**").hasRole("" + UserEnum.ADMIN)
.anyRequest().permitAll()
);
return http.build();
}
public CorsConfigurationSource configurationSource() {
log.debug("디버그 : configurationSource cors 설정이 SecurityFilterChain에 등록됨");
CorsConfiguration configuration = new CorsConfiguration();
configuration.addAllowedHeader("*");
configuration.addAllowedMethod("*"); // GET, POST, PUT, DELETE (Javascript 요청 허용)
configuration.addAllowedOriginPattern("*"); // 모든 IP 주소 허용 (프론트 앤드 IP만 허용 react)
configuration.setAllowCredentials(true); // 클라이언트에서 쿠키 요청 허용
configuration.addExposedHeader("Authorization"); // 옛날에는 디폴트 였다. 지금은 아닙니다.
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", configuration);
return source;
}
}
요청/응답 DTO 관련 문의
0
170
2
안녕하세요 인증이 필요한 url을 위하여 /s를 붙이는것에 대해 질문있습니다.
0
161
1
validation aop사용에 대해서 질문있습니다.
0
245
2
Dummy 클래스 위치에 대한 질문
0
293
2
테스트 방식에 관해서 질문이 있어요
0
292
2
스프링 버전업일 경우에는 Pointcut @PostMapping 조건이 달라질까요?
1
434
1
equals와 longValue 관련 질문드립니다
0
329
1
계좌번호를 Long 타입으로 하는 이유가 무엇일까요?!
0
499
2
[정보공유] Hibernate 로그 작동 안하시는 분들!!
3
346
0
UserControllerTest 테스트 실패 문의
0
318
1
import 오류
0
427
3
spring initializer gradle 에서 3.x.x 대 밖에 없어요. 2.x.x는 보이지 않는데 어떡하져
0
438
2
안녕하세요 로그엔 성공적으로 들어온것같습니다..
0
237
1
JwtAuthorizationfilter test mvc.performget 관련 질문입니다!
0
287
1
JwtAuthorizationfilter test mvc.performget 부
0
226
1
longValue() 질문
0
228
1
jwt 인가필터 규현및 등록
0
334
1
스프링부트 3버전
1
334
1
권한처리를 위한 세션강제주입
0
418
1
JwtVO 를 인터페이스로 만든 이유
0
359
1
계좌 조회 질문드립니다
0
229
1
DummyObject 에 대하여
0
308
2
DTO를 이너클래스로 계속추가하는 이유
0
695
2
Builder 사용 궁금
0
404
1

