【问题标题】:Spring Security in Spring Boot 3Spring Boot 3 中的 Spring Security
【发布时间】:2022-12-14 00:37:32
【问题描述】:

我目前正在将我们的 REST 应用程序从 Spring Boot 2.7.5 迁移到 3.0.0-RC2。除了 Open API URL 之外,我希望所有内容都是安全的。在 Spring Boot 2.7.5 中,我们曾经这样做过:

@Named
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

  @Override
  protected void configure(HttpSecurity http) throws Exception {
    http.authorizeRequests()
        .antMatchers("/openapi/openapi.yml").permitAll()
        .anyRequest().authenticated()
        .and()
        .httpBasic();
  }
}

它工作正常。在 Spring Boot 3 中,我不得不将其更改为

@Configuration
@EnableWebSecurity
public class WebSecurityConfig {

  @Bean
  public SecurityFilterChain configure(HttpSecurity http) throws Exception {
    http.authorizeHttpRequests((requests) -> requests
            .requestMatchers("/openapi/openapi.yml").permitAll()
            .anyRequest()
            .authenticated())
        .httpBasic();

    return http.build();
  }
}

因为 WebSecurityConfigurerAdapter 已被删除。虽然它不起作用。 Open API URL 也通过基本身份验证得到保护。升级代码时我是否犯了错误,或者这可能是 Spring Boot 3 RC 2 中的问题?

更新由于大多数新 API 已在 2.7.5 中可用,我已将 2.7.5 代码库中的代码更新为以下内容:

@Configuration
@EnableWebSecurity
public class WebSecurityConfig {

  @Bean
  public SecurityFilterChain configure(HttpSecurity http) throws Exception {
    http
        .csrf().disable()
        .authorizeHttpRequests((requests) -> requests
            .antMatchers(OPTIONS).permitAll() // allow CORS option calls for Swagger UI
            .antMatchers("/openapi/openapi.yml").permitAll()
            .anyRequest().authenticated())
        .httpBasic();
    return http.build();
  }
}

在我们的 3.0.0-RC2 分支中,代码如下:

@Configuration
@EnableWebSecurity
public class WebSecurityConfig {

  @Bean
  public SecurityFilterChain configure(HttpSecurity http) throws Exception {
    http
        .csrf().disable()
        .authorizeHttpRequests((requests) -> requests
            .requestMatchers(OPTIONS).permitAll() // allow CORS option calls for Swagger UI
            .requestMatchers("/openapi/openapi.yml").permitAll()
            .anyRequest().authenticated())
        .httpBasic();
    return http.build();
  }
}

如您所见,唯一的区别是我调用了 requestMatchers 而不是 antMatchers。此方法似乎已重命名。 antMatchers 方法不再可用。最终效果仍然是一样的。在我们的 3.0.0-RC2 分支上,Spring Boot 要求对 OpenAPI URL 进行基本身份验证。在 2.7.5 上仍然可以正常工作。

【问题讨论】:

  • 我可能应该提到我正在使用 Jersey。也许这与它有关?
  • 你真的有"/openapi/openapi.yml"的处理程序(控制器映射)吗?如果没有handler,则解析为not404 NOT_FOUND。这又重定向到/error。由于/error 也受到保护,因此它会要求您登录。
  • 是的,我愿意。一旦我输入基本身份验证的凭据,就会显示 Open API。
  • 可能是匹配器。 requests.antMatchers("/openapi/openapi.yml").permitAll() 是不是还是可以的?
  • 不,我刚刚对问题进行了更新。 antMatchers 方法不再可用。

标签: spring-boot spring-security spring-boot-3


【解决方案1】:

作者:https://github.com/wilkinsona

  @Bean
  public SecurityFilterChain configure(HttpSecurity http) throws Exception {
    http
        .authorizeHttpRequests((requests) -> requests
            .requestMatchers(new AntPathRequestMatcher("/openapi/openapi.yml")).permitAll()
            .anyRequest().authenticated())
        .httpBasic();
    return http.build();
  }

来源:https://github.com/spring-projects/spring-boot/issues/33357#issuecomment-1327301183

我建议您现在使用 Spring Boot 3.0.0 (GA),而不是 RC 版本。

【讨论】:

    【解决方案2】:

    官方文档建议了一个示例,我已在此处使用您的配置进行了删减:

    http
      .authorizeExchange((exchanges) ->
        exchanges
          .pathMatchers("/openapi/openapi.yml").permitAll()
          .anyExchange().authenticated())
        .httpBasic();
    
    return http.build();
    

    你可以试试这个,因为它改变了“交换”措辞的“请求”,与我想的向声明式客户端的迁移(@PostExchange 与 @PostMapping)一致。希望能帮助到你。

    【讨论】:

    【解决方案3】:

    利用

      http.securityMatcher("<patterns>")...
    

    指定端点的身份验证。

          authorizeHttpRequests((requests) -> requests
                    .requestMatchers("<pattern>")
    

    仅适用于授权,如果您未设置 securityMatcher ,则 SecurityFilterChain 默认获取 any request 进行身份验证。并且任何请求都将由身份验证提供程序进行身份验证。

    在您的情况下,您可以定义两个安全过滤器链:一个用于公共端点,另一个用于安全。并给他们正确的顺序:

        @Bean
        @Order(1)
        public SecurityFilterChain configure(HttpSecurity http) throws Exception {
            http.securityMatcher(OPTIONS,"/openapi/openapi.yml").csrf().disable()
                .authorizeHttpRequests((requests) -> requests
                    .anyRequest().permitAll() // allow CORS option calls for Swagger UI
        );
            return http.build();
          }
        
        @Bean
        Order(2)
          public SecurityFilterChain configure(HttpSecurity http) throws Exception {
            http.securityMatcher("/**")
                .csrf().disable()
                .authorizeHttpRequests((requests) -> requests.anyRequest().authenticated())
                .httpBasic();
            return http.build();
          }
    

    【讨论】:

    • 这似乎不必要地复杂。我接受了 Andy Wilkinson 的建议(见 James Grey 的回答)
    【解决方案4】:

    在我的 WebSecurityConfig 中,我这样做了:

    private static final String[] AUTH_WHITELIST = {
                // -- Swagger UI v2
                "/v2/api-docs",
                "v2/api-docs",
                "/swagger-resources",
                "swagger-resources",
                "/swagger-resources/**",
                "swagger-resources/**",
                "/configuration/ui",
                "configuration/ui",
                "/configuration/security",
                "configuration/security",
                "/swagger-ui.html",
                "swagger-ui.html",
                "webjars/**",
                // -- Swagger UI v3
                "/v3/api-docs/**",
                "v3/api-docs/**",
                "/swagger-ui/**",
                "swagger-ui/**",
                // CSA Controllers
                "/csa/api/token",
                // Actuators
                "/actuator/**",
                "/health/**"
        };
    
        @Bean
        public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
            return http
                    .csrf(AbstractHttpConfigurer::disable)
                    .authorizeHttpRequests( auth -> auth
                            .requestMatchers(AUTH_WHITELIST).permitAll()
                            .anyRequest().authenticated()
                    )
                    .sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
                    .httpBasic(withDefaults())
                    .addFilterBefore(authenticationJwtTokenFilter, UsernamePasswordAuthenticationFilter.class)
                    //.addFilterAfter(authenticationJwtTokenFilter, UsernamePasswordAuthenticationFilter.class)
                    .build();
        }
    
        @Bean
        public SecurityFilterChain configure(HttpSecurity httpSecurity) throws Exception {
            httpSecurity
                    .authorizeHttpRequests((requests) -> requests
                            .requestMatchers( new AntPathRequestMatcher("swagger-ui/**")).permitAll()
                            .requestMatchers( new AntPathRequestMatcher("/swagger-ui/**")).permitAll()
                            .requestMatchers( new AntPathRequestMatcher("v3/api-docs/**")).permitAll()
                            .requestMatchers( new AntPathRequestMatcher("/v3/api-docs/**")).permitAll()
                            .anyRequest().authenticated())
                    .httpBasic();
            return httpSecurity.build();
        }
    

    这一点,加上使用 Dockerfile(执行 mvn clean package 并从 Docker 运行 jar)使我在 swagger ui 中的身份验证没有问题。

    希望这可以帮到你 :)

    【讨论】:

      【解决方案5】:

      这似乎是 Spring Boot 3 中的一个错误。我提出了一个issue

      【讨论】:

      • 我认为不是,请检查 HttpSecurity 的 securityMatcher() 方法
      猜你喜欢
      • 2018-10-23
      • 2017-09-11
      • 2021-09-07
      • 2019-07-16
      • 2015-06-09
      • 2019-02-18
      • 1970-01-01
      • 1970-01-01
      • 2014-12-07
      相关资源
      最近更新 更多