개인 프로젝트의 Spring boot 버전을 3.2 로 업데이트 하는 과정에서 deprecated 된 함수를 발견해서, 해결했던 방법을 기록한다.
문제가 된 코드는 Spring Security 의 FilterChain 을 정의하는 이부분에서 발생했다.
@Bean
@Profile("jpa-oauth-server")
public SecurityFilterChain filterChain(HttpSecurity httpSecurity,
RegisteredClientRepository registeredClientRepository,
OAuth2AuthorizationService authorizationService,
OAuth2AuthorizationConsentService oAuth2AuthorizationConsentService,
JwtEncoder jwtEncoder,
AuthorizationServerSettings settings) throws Exception {
...
httpSecurity
.authorizeHttpRequests(authorize ->
authorize.anyRequest().authenticated()
)
.csrf(csrf -> csrf.ignoringRequestMatchers(endpointsMatcher))
// DEPRECATED in 6.2
.apply(authorizationServerConfigurer);
바로 Spring Security 에서 CustomConfigurer 를 적용하는 .apply 함수가 Spring Security 6.2 부터 Deprecated 되었다. 링크를 따라가보면 ” For removal in 7.0. Use AbstractConfiguredSecurityBuilder.with(SecurityConfigurerAdapter, Customizer)
instead. ” 라고 명시되어 있다.
내용은 7.0 부터 사라질 예정이니 .with() 를 사용하라는 건데, 코드를 살펴보자.
@Deprecated(
since = "6.2",
forRemoval = true
)
public <C extends SecurityConfigurerAdapter<O, B>> C apply(C configurer) throws Exception {
configurer.addObjectPostProcessor(this.objectPostProcessor);
configurer.setBuilder(this);
this.add(configurer);
return configurer;
}
public <C extends SecurityConfigurer<O, B>> C apply(C configurer) throws Exception {
this.add(configurer);
return configurer;
}
public <C extends SecurityConfigurerAdapter<O, B>> B with(C configurer, Customizer<C> customizer) throws Exception {
configurer.addObjectPostProcessor(this.objectPostProcessor);
configurer.setBuilder(this);
this.add(configurer);
customizer.customize(configurer);
return this;
}
기존에 사용하던 .apply 는 deprecated 되고, 기존에 못보던 .with( ) 라는 함수가 생겨난것을 확인할 수 있다. 소스를 보면 거의 동일한 역할을 하는 함수인데 customizer.customize(configurer) 가 추가되고 Return type 이 변경된 것이 전부이다.
해결 방법
가장 쉬운 방법은 Docs 에서 설명하는대로 .apply 를 .with 로 대체하는 방법이다. Customizer는 기본값으로, 기존과 동일하게 유지하려면 그냥 Customizer.withDefaults() 를 적용하면 된다.
@Bean
@Profile("jpa-oauth-server")
public SecurityFilterChain filterChain(HttpSecurity httpSecurity,
RegisteredClientRepository registeredClientRepository,
OAuth2AuthorizationService authorizationService,
OAuth2AuthorizationConsentService oAuth2AuthorizationConsentService,
JwtEncoder jwtEncoder,
AuthorizationServerSettings settings) throws Exception {
...
httpSecurity
.authorizeHttpRequests(authorize ->
authorize.anyRequest().authenticated()
)
.csrf(csrf -> csrf.ignoringRequestMatchers(endpointsMatcher))
// DEPRECATED in 6.2
// .apply(authorizationServerConfigurer) 이것과 동일하게 작동한다.
.with(authorizationServerConfigurer, Customizer.withDefaults());
하지만 하지만, .apply 가 deprecated 되고 Customizer 라는 Functional Interface 가 추가된 만큼 기존의 코드를 조금 리팩토링했다.
기존에 사용하던 Configurer 코드 중에 같은 OAuth2AuthorizationServerConfigurer 의 설정값을 변경하는 부분이 있다.
httpSecurity.getConfigurer(OAuth2AuthorizationServerConfigurer.class)
.oidc(Customizer.withDefaults())
.registeredClientRepository(registeredClientRepository)
// .clientAuthentication(clientConfigurer -> clientConfigurer.authenticationProvider(provider))
.authorizationService(authorizationService)
.authorizationConsentService(oAuth2AuthorizationConsentService)
.tokenGenerator(new JwtGenerator(jwtEncoder))
.authorizationServerSettings(settings);
기존 코드는 .apply 를 통해 configurer 를 적용한 뒤 다시 getConfigurer 를 통해 가져와 설정값을 적용했는데, 이부분을 다음과 같이 이런 식으로 변경할 수 있다.
//Before
@Bean
@Profile("jpa-oauth-server")
public SecurityFilterChain filterChain(HttpSecurity httpSecurity,
RegisteredClientRepository registeredClientRepository,
OAuth2AuthorizationService authorizationService,
OAuth2AuthorizationConsentService oAuth2AuthorizationConsentService,
JwtEncoder jwtEncoder,
AuthorizationServerSettings settings) throws Exception {
...
httpSecurity
.authorizeHttpRequests(authorize ->
authorize.anyRequest().authenticated()
)
.csrf(csrf -> csrf.ignoringRequestMatchers(endpointsMatcher))
.apply(authorizationServerConfigurer);
httpSecurity.getConfigurer(OAuth2AuthorizationServerConfigurer.class)
.oidc(Customizer.withDefaults())
.registeredClientRepository(registeredClientRepository)
.authorizationService(authorizationService)
.authorizationConsentService(oAuth2AuthorizationConsentService)
.tokenGenerator(new JwtGenerator(jwtEncoder))
.authorizationServerSettings(settings);
//After
@Bean
@Profile("jpa-oauth-server")
public SecurityFilterChain filterChain(HttpSecurity httpSecurity,
RegisteredClientRepository registeredClientRepository,
OAuth2AuthorizationService authorizationService,
OAuth2AuthorizationConsentService oAuth2AuthorizationConsentService,
JwtEncoder jwtEncoder,
AuthorizationServerSettings settings) throws Exception {
...
httpSecurity
.authorizeHttpRequests(authorize ->
authorize.anyRequest().authenticated()
)
.csrf(csrf -> csrf.ignoringRequestMatchers(endpointsMatcher))
// DEPRECATED in 6.2
// .apply(authorizationServerConfigurer)
.with(authorizationServerConfigurer, oAuth2AuthorizationServerConfigurer -> {
oAuth2AuthorizationServerConfigurer
.oidc(Customizer.withDefaults())
.registeredClientRepository(registeredClientRepository)
.authorizationService(authorizationService)
.authorizationConsentService(oAuth2AuthorizationConsentService)
.tokenGenerator(new JwtGenerator(jwtEncoder))
.authorizationServerSettings(settings);
});
함수형 인터페이스를 통해 훨씬 더 간결하게 사용할 수 있게 된 것 같다.
여담
이미 작성되어 있는 코드들을 리팩토링 할 때, Customizer.withDefaults() 를 많이 사용하게 될 텐데, 그 때문에 .with( ) 메소드의 두번째 인자로 Customizer.withDefaults 를 사용하는 함수를 overloading 해 달라는 issue 가 있으나, 답변은 No 인 상황이다. ( 자세한 이유는 이슈에서 확인하자. )