Spring Boot / h2-console使用Spring Security 1.5.2抛出403

时间:2017-05-05 00:30:28

标签: spring spring-boot spring-security

我们最近从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-console。

8 个答案:

答案 0 :(得分:11)

由于H2拥有自己的身份验证提供程序,因此您可以完全以与静态内容相同的方式跳过Spring Security进入h2控制台的路径。

为此,在您的Spring安全配置中,您必须重写将org.springframework.security.config.annotation.web.builders.WebSecurity实例作为参数的配置方法,而不是将org.springframework.security.config.annotation.web.builders.HttpSecurity实例作为参数的配置方法< / p>

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

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

答案 1 :(得分:9)

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

要访问H2控制台,只需将以下代码添加到WebSecurityConfigurer中。

@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();
    }
}

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

答案 2 :(得分:3)

我启用了调试日志记录并看到了:

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&gt; ROLE_USER但我仍然需要更好地理解这一点。

我将设置更新为:

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

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

答案 3 :(得分:2)

@Configuration
@ConditionalOnClass(WebSecurityConfigurerAdapter.class)
@ConditionalOnBean(ObjectPostProcessor.class)
@ConditionalOnProperty(prefix = "security.basic", name = "enabled", matchIfMissing = true)
static class H2ConsoleSecurityConfiguration 

正如您可以在spring boot中从源代码中读取的那样,如果启用basic,则spring boot将加载带有H2ConsoleSecurityConfigurer命令的spring security配置SecurityProperties.BASIC_AUTH_ORDER - 10,并且身份验证基于您的配置安全。这是默认的安全配置:

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();
        }

    }

答案 4 :(得分:1)

当我使用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()

答案 5 :(得分:0)

我想提供与@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,而另一个不禁止,则请求将不会通过第一个链。.也就是说,请谨慎使用多个配置器。

答案 6 :(得分:0)

这对我也有帮助

  #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

答案 7 :(得分:0)

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

@SpringBootApplication(exclude = SecurityAutoConfiguration.class)

像这一行一样改变这部分。

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