我正在try 升级到Spring Boot 3.0.0和Spring Security6.0.

我发现保护请求authorizeRequests()的方法已被弃用.并且方法antMatchers()@EnableGlobalMethodSecurity注释也被移除.如何通过安全配置进行升级?

My code:

package org.sid.securityservice.config;

import com.nimbusds.jose.jwk.JWK;
import com.nimbusds.jose.jwk.JWKSet;
import com.nimbusds.jose.jwk.RSAKey;
import com.nimbusds.jose.jwk.source.ImmutableJWKSet;
import com.nimbusds.jose.jwk.source.JWKSource;
import com.nimbusds.jose.proc.SecurityContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.ProviderManager;
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
import org.springframework.security.config.Customizer;
import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configurers.oauth2.server.resource.OAuth2ResourceServerConfigurer;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.oauth2.jwt.JwtDecoder;
import org.springframework.security.oauth2.jwt.JwtEncoder;
import org.springframework.security.oauth2.jwt.NimbusJwtDecoder;
import org.springframework.security.oauth2.jwt.NimbusJwtEncoder;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
import org.springframework.security.web.SecurityFilterChain;

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig {
    private RsakeysConfig rsakeysConfig;
    private PasswordEncoder passwordEncoder;

    public SecurityConfig(RsakeysConfig rsakeysConfig, PasswordEncoder passwordEncoder) {
        this.rsakeysConfig = rsakeysConfig;
        this.passwordEncoder = passwordEncoder;
    }

    //@Bean
    public AuthenticationManager authenticationManager(AuthenticationConfiguration authenticationConfiguration) throws Exception {
        return authenticationConfiguration.getAuthenticationManager();
    }
    @Bean
    public AuthenticationManager authenticationManager(UserDetailsService userDetailsService){
        var authProvider = new DaoAuthenticationProvider();
        authProvider.setPasswordEncoder(passwordEncoder);
        authProvider.setUserDetailsService(userDetailsService);
        return new ProviderManager(authProvider);
    }

    @Bean
    public UserDetailsService inMemoryUserDetailsManager(){
        return new InMemoryUserDetailsManager(
                User.withUsername("user1").password(passwordEncoder.encode("1234")).authorities("USER").build(),
                User.withUsername("user2").password(passwordEncoder.encode("1234")).authorities("USER").build(),
                User.withUsername("admin").password(passwordEncoder.encode("1234")).authorities("USER","ADMIN").build()
        );
    }
    @Bean
    public SecurityFilterChain filterChain(HttpSecurity httpSecurity) throws Exception {
        return httpSecurity
                .csrf(csrf->csrf.disable())
                .authorizeRequests(auth->auth.antMatchers("/token/**").permitAll())
                .authorizeRequests(auth->auth.anyRequest().authenticated())
                .sessionManagement(sess->sess.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
                .oauth2ResourceServer(OAuth2ResourceServerConfigurer::jwt)
                .httpBasic(Customizer.withDefaults())
                .build();
    }
    @Bean
    JwtDecoder jwtDecoder(){
        return NimbusJwtDecoder.withPublicKey(rsakeysConfig.publicKey()).build();
    }
    @Bean
    JwtEncoder jwtEncoder(){
        JWK jwk= new RSAKey.Builder(rsakeysConfig.publicKey()).privateKey(rsakeysConfig.privateKey()).build();
        JWKSource<SecurityContext> jwkSource= new ImmutableJWKSet<>(new JWKSet(jwk));
        return new NimbusJwtEncoder(jwkSource);
    }

}

以下是IDE向我展示的内容(go 掉authorizeRequests()个,缺少antMatchers()个,用红色突出显示):

enter image description here

推荐答案

在Spring Security 6.0中,安全请求(namelymvcMathcers()andregexMatchers())的其他配置方法(namelymvcMathcers()andregexMatchers())已经从API中得到了removed.

引入重载方法requesMatchers()作为保护请求的统一手段.requesMatchers()的风格促进了限制被删除的方法所支持的请求的所有方式.

此外,方法authorizeRequests()已经是deprecated,不应该再使用了.建议更换-authorizeHttpRequests()(you can find more information regarding these changes 101).

在Spring Security 6.0中,您的SecurityFilterChain可能就是这样定义的:

public SecurityFilterChain filterChain(HttpSecurity httpSecurity) throws Exception {
    return httpSecurity
        .csrf(csrf -> csrf.disable())
        .authorizeHttpRequests(auth -> auth
            .requestMatchers("/token/**").permitAll()
            .anyRequest().authenticated()
        )
        .sessionManagement(sess -> sess.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
        .oauth2ResourceServer(OAuth2ResourceServerConfigurer::jwt)
        .httpBasic(Customizer.withDefaults())
        .build();
}

对于不建议使用的注释@EnableGlobalMethodSecurity,它被替换为@EnableMethodSecurity.此更改背后的原因是,启用@PreAuthorize/@PostAuthorize所需的@EnableMethodSecurity属性prePostEnabled@PreFilter/@PostFilter缺省设置为true.

因此,您不再需要编写prePostEnabled = true,只需用@EnableMethodSecurity来注释您的配置类就足够了.

Java相关问答推荐

即使我正在使用并发方法,使用Javascript的应用程序也会继续冻结'

如果一个子类没有构造函数,超类也没有构造函数,那么为什么我可以构造子类的实例呢?

Java函数式编程中的双值单值映射

如何才能使我的程序不会要求两次输入?

为什么Spring Boot项目无法为基于MySQL的CRUD应用程序找到从JPARepository接口扩展的ProductRepository?

将PNG转换为位图自定义十六进制字符串

如何在 spring 数据的MongoDB派生查询方法中使用$EXISTS

如何在JavaFX循环中完美地制作一个AudioClip/MediaPlayer?

如何在Record Java中使用isRecord()和RecordComponent[]?

在整数列表中查找和可被第三个整数整除的对时出现无法解释的RunTimeError

在Oracle中调用输出参数在索引处缺少IN或OUT参数的函数

Java类型推断:为什么要编译它?

获取401未经授权,即使在标头中设置了浏览器名称和cookie

转换为JSON字符串时,日期按天递减-Java

在JSON上获取反斜杠

@此处不能应用可为null的批注

带有提取器的JavaFXObservableList会根据侦听器的存在而改变行为

在JPanel上使用GridBagLayout并将JButton放在里面时出现问题

为什么 static Thread.currentThread().getName() 和 getName() 之间有区别?

如何用Android Java直接执行http命令?