【问题标题】:Spring Boot /h2-console throws 403 with Spring Security 1.5.2Spring Boot /h2-console 使用 Spring Security 1.5.2 抛出 403
【发布时间】:2017-10-03 07:58:05
【问题描述】:

我们最近从 Spring Boot 1.4.1 升级到了 1.5.2。 1.5.2 的特性之一是,如果 Spring Security 是包的一部分,那么它受到基本身份验证的保护。即使经过基本身份验证,我也无法访问/h2-console。它抛出 403 禁止。

application.yml:

spring:
  datasource:
    driver-class-name: org.h2.Driver
    url: jdbc:h2:file:../app-db/app_db;AUTO_SERVER=TRUE
    username: sa
    password: sa
    initialize: false
  jpa:
    hibernate:
      ddl-auto: validate
    show-sql: true
    database-platform: org.hibernate.dialect.H2Dialect
  h2:
    console:
      enabled: true
      settings:
        web-allow-others: true
  allowed:
    resources: /h2-console/**

我什至明确允许/h2-console/**

 httpSecurity.authorizeRequests()
                .antMatchers(allowedResources)                  
                .permitAll()

我在尝试访问 localhost:8080/h2-console 时不断收到 403。 我尝试了许多设置以及放置:

management.security.enabled=true
security.basic.enabled=true

但我无法访问 h2 控制台。

【问题讨论】:

  • 你有没有在 github 上用安全性在 Spring Boot 上引用这个 example

标签: spring spring-boot spring-security


【解决方案1】:

Spring 安全阻止 H2 数据库的 /h2-console(或您在 application.yaml 中配置的路径)路径。

要访问 H2 控制台,只需将以下代码添加到您的 WebSecurityConfigurerAdapter。

@Configuration
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                .antMatchers("/").permitAll()
                .antMatchers("/h2-console/**").permitAll();

        http.csrf().disable();
        http.headers().frameOptions().disable();
    }
}

请勿在生产环境中使用此配置。 =)

【讨论】:

  • 不应该是h2-console吗?
  • 实际上它可以是你定义的任何东西。我将其更新为标准方式。谢谢@theprogrammer。
  • 看起来@Para D 的答案现在是正确的:web.ignoring().antMatchers("/h2-console/**")
  • @MetalRules,确切地说,这个没有帮助。
【解决方案2】:

由于 H2 有自己的身份验证提供程序,因此您可以完全跳过 Spring Security 来处理 h2 控制台的路径,就像处理静态内容一样。

为了做到这一点,在您的 Spring 安全配置中,您必须覆盖将 org.springframework.security.config.annotation.web.builders.WebSecurity 实例作为参数的配置方法,而不是采用 org.springframework.security.config.annotation.web.builders.HttpSecurity 实例的配置方法

    @Override
    public void configure(WebSecurity web) throws Exception {
        web
            .ignoring()
            .antMatchers("/h2-console/**");
    }

如果您在生产环境中使用 h2,请确保为您的 h2 控制台设置适当的安全措施(例如,设置非显而易见的路径、正确的密码、ip 白名单)。

【讨论】:

  • 非常感谢。这是 2020 年有效的实际答案。
  • 比公认的答案容易得多,在 v2.2 中运行良好。
  • 看来这是最好的答案了。
  • 完美答案,用spring boot版本测试:2.2.2.RELEASE,h2版本:1.4.200
【解决方案3】:

我想提供类似于@argoth 所提议的配置,但更适合生产:)

@Profile("h2") // to make sure it is active only if h2 profile is active
@Configuration
@ConditionalOnProperty( //to make sure it is active if console is enabled
    value="spring.h2.console.enabled", 
    havingValue = "true", 
    matchIfMissing = false)
public class H2SecurityConfiguration extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        // this may not be required, depends on your app configuration
        http.authorizeRequests()
                // we need config just for console, nothing else             
                .antMatchers("/h2_console/**").permitAll();
        // this will ignore only h2-console csrf, spring security 4+
        http.csrf().ignoringAntMatchers("/h2-console/**");
        //this will allow frames with same origin which is much more safe
        http.headers().frameOptions().sameOrigin();
    }
}

事实上,在启动 1.3 中进行了类似的配置,称为 H2ConsoleSecurityConfiguration,但现在它已经消失了: Old class

github discussion

更新。非常重要的注意事项!当您有多个WebSecurityConfigurerAdapter 时,它们可能会相互冲突,因此如果您的代码中有另一个WebSecurityConfigurerAdapter,则需要以某种方式合并它们。为了向您详细说明为什么会发生冲突,这是由于每个适配器都设置了自己的过滤器链,并且每个请求都必须通过两个过滤器链。如果其中一个链禁止 frameOptions 而另一个不禁止,则请求不会通过第一个链。也就是说,请小心使用多个配置器。

【讨论】:

    【解决方案4】:
    @Configuration
    @ConditionalOnClass(WebSecurityConfigurerAdapter.class)
    @ConditionalOnBean(ObjectPostProcessor.class)
    @ConditionalOnProperty(prefix = "security.basic", name = "enabled", matchIfMissing = true)
    static class H2ConsoleSecurityConfiguration 
    

    正如你在spring boot中看到的源代码,如果你启用了basic,spring boot会以SecurityProperties.BASIC_AUTH_ORDER - 10的顺序加载spring security配置H2ConsoleSecurityConfigurer,认证基于你在security中的配置。这是默认的安全配置:

    public void configure(HttpSecurity http) throws Exception {
                String path = this.console.getPath();
                String antPattern = path.endsWith("/")?path + "**":path + "/**";
                HttpSecurity h2Console = http.antMatcher(antPattern);
                h2Console.csrf().disable();
                h2Console.httpBasic();
                h2Console.headers().frameOptions().sameOrigin();
                // the default role is `USER` and `management.security.roles`
                String[] roles = (String[])this.security.getUser().getRole().toArray(new String[0]);
               // this value is base `security.basic.authorize-mode`, `role`, 'authenticated' and `none`
                SecurityAuthorizeMode mode = this.security.getBasic().getAuthorizeMode();
                if(mode != null && mode != SecurityAuthorizeMode.ROLE) {
                    if(mode == SecurityAuthorizeMode.AUTHENTICATED) {
                        ((AuthorizedUrl)http.authorizeRequests().anyRequest()).authenticated();
                    }
                } else {
                    ((AuthorizedUrl)http.authorizeRequests().anyRequest()).hasAnyRole(roles);
                }
    
            }
    

    您还可以创建一个新配置来覆盖默认配置。

    @Configuration
    // before the default configuration
    @Order(SecurityProperties.BASIC_AUTH_ORDER - 11)
    class CustomH2ConsoleSecurityConfigurer extends WebSecurityConfigurerAdapter {
    
            @Autowired
            private H2ConsoleProperties console;
    
            @Override
            public void configure(HttpSecurity http) throws Exception {
                String path = this.console.getPath();
                String antPattern = (path.endsWith("/") ? path + "**" : path + "/**");
                HttpSecurity h2Console = http.antMatcher(antPattern);
                h2Console.csrf().disable();
                h2Console.httpBasic();
                h2Console.headers().frameOptions().sameOrigin();
                // config as you like
                http.authorizeRequests().anyRequest().permitAll();
            }
    
        }
    

    【讨论】:

      【解决方案5】:

      我启用了调试日志并看到了这个:

      o.s.s.w.a.i.FilterSecurityInterceptor    : Secure object: FilterInvocation: URL: /h2-console/; Attributes: [hasAnyRole('ROLE_USER','ROLE_ACTUATOR')]
      2017-05-05 13:16:09.304 DEBUG 90365 --- [nio-8080-exec-2] o.s.s.w.a.i.FilterSecurityInterceptor    : Previously Authenticated: org.springframework.security.authentication.UsernamePasswordAuthenticationToken@33d2af72: Principal: org.springframework.security.ldap.userdetails.LdapUserDetailsImpl@7371d5f4: Dn: cn=XYZ,ou=XYZ,ou=Active,ou=ABC_USERS,dc=internal,dc=organization,dc=com; Username: uname; Password: [PROTECTED]; Enabled: true; AccountNonExpired: true; CredentialsNonExpired: true; AccountNonLocked: true; Granted Authorities: ROLE_ADMIN; Credentials: [PROTECTED]; Authenticated: true; Details: org.springframework.security.web.authentication.WebAuthenticationDetails@b364: RemoteIpAddress: 0:0:0:0:0:0:0:1; SessionId: 86EF50EF548ED4DBCE4D661AEC93F88C; Granted Authorities: ROLE_ADMIN
      2017-05-05 13:16:09.305 DEBUG 90365 --- [nio-8080-exec-2] o.s.s.access.vote.AffirmativeBased       : Voter: org.springframework.security.web.access.expression.WebExpressionVoter@51d3d69, returned: -1
      2017-05-05 13:16:09.305 DEBUG 90365 --- [nio-8080-exec-2] o.s.s.w.a.ExceptionTranslationFilter     : Access is denied (user is not anonymous); delegating to AccessDeniedHandler
      

      我意识到我的用户没有ROLE_USER。我假设ROLE_ADMIN > ROLE_USER 但我仍然需要更好地理解这一点。

      我将设置更新为:

      security:
        basic:
          enabled: true
          authorize-mode: NONE
      

      我现在可以访问/h2-console/**

      【讨论】:

      • 你可以在我的回答中看到我的 cmets。
      • 这不会破坏身份验证吗?
      • 授权已启用,因此如果用户没有分配角色,她将被拒绝访问
      【解决方案6】:

      我在使用 spring security 时也遇到了同样的问题。请注意 application.properties 中的以下配置

      spring.h2.console.enabled=true
      spring.h2.console.path=/h2
      
      spring.datasource.url=jdbc:h2:file:~/test
      spring.datasource.username=sa
      spring.datasource.password=
      spring.datasource.driver-class-name=org.h2.Driver
      

      在 configure 方法下的安全配置中,我包含了以下内容,并且可以访问 h2 控制台。

              .antMatchers( "/h2/**").permitAll()
      

      【讨论】:

        【解决方案7】:

        这对我也有帮助

          #H2 database
            datasource:
              url: jdbc:h2:mem:mytestdb;INIT=RUNSCRIPT FROM 'classpath:/data.sql'
              driverClassName: org.h2.Driver
              username: sa
              password: sa
            main:
                allow-bean-definition-overriding: true
            h2:
              console:
                enabled: true
                path: /h2-console
                settings:
                  web-allow-others: true
            allowed:
              resources: /h2-console/**
            security:
              basic:
                enabled: true
                authorize-mode: NONE
        

        【讨论】:

          【解决方案8】:

          这可能是一个安全问题。在应用程序中

          @SpringBootApplication(exclude = SecurityAutoConfiguration.class)

          像这行一样改变这部分。

          我希望你能解决这个问题。

          【讨论】:

            【解决方案9】:

            关于WebSecurityConfigurerAdapter,我认为更合适且解释清楚的答案是available here 虽然我已经添加了示例代码并且它对我来说很好用,不仅适用于 h2-console,而且适用于 Swagger-UI

            private static final String[] AUTH_WHITELIST = {
                    // -- Swagger UI v2
                    "/v2/api-docs",
                    "/swagger-resources",
                    "/swagger-resources/**",
                    "/configuration/ui",
                    "/configuration/security",
                    "/swagger-ui.html",
                    "/webjars/**",
                    // -- Swagger UI v3 (OpenAPI)
                    "/v3/api-docs/**",
                    "/swagger-ui/**",
                    // other public endpoints
                    "/h2-console/**",
             };
            @Override
            protected void configure(HttpSecurity http) throws Exception {
                    http.csrf().disable().authorizeRequests().antMatchers("/hello").hasAuthority("USER")
                            .and().authorizeRequests().antMatchers(AUTH_WHITELIST).permitAll().anyRequest().authenticated()
                            .and().headers().frameOptions().sameOrigin()
                            .and().sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);            
            }
            

            【讨论】:

              猜你喜欢
              • 2017-01-16
              • 2018-07-11
              • 2023-03-26
              • 2021-02-26
              • 1970-01-01
              • 2017-12-24
              • 2023-02-08
              • 2021-01-09
              • 2020-12-10
              相关资源
              最近更新 更多