Spring Boot /h2-console在使用Spring Security 1.5.2时会出现403错误

45
我们最近将Spring Boot从1.4.1升级到1.5.2。 1.5.2的一个功能是,如果Spring Security是包的一部分,则受基本身份验证保护。即使进行了基本身份验证,我也无法访问/h2-console。 它会抛出403 forbidden的错误。
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和安全性的示例吗?链接如下:https://github.com/spring-projects/spring-boot/tree/master/spring-boot-samples/spring-boot-sample-web-secure-custom - Rajith Pemabandu
17个回答

97

由于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白名单等)。


15
非常感谢。这是2020年确实有效的答案。 - theprogrammer
5
比起被接受的答案要简单得多,在 v2.2 中运行良好。 - Ava
2
似乎这是最佳答案。 - mazend
完美的答案,已经测试过了,使用的是Spring Boot版本:2.2.2.RELEASE,H2版本:1.4.200。 - IuR
2
仅有这些还不够。我们还需要设置X-Frame-Options,否则现代浏览器将拒绝在h2-console中呈现框架。这个答案更完整:https://dev59.com/hlcP5IYBdhLWcg3w0dKU#69899965 - lorefnon
1
谢谢!它有效! - Sankalpa Wijewickrama

84

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
实际上它可以是你定义的任何东西。我将其更新为标准方式。谢谢@theprogrammer。 - argoth
7
看起来@Para D的答案现在是正确的:web.ignoring().antMatchers("/h2-console/**") - MetalRules
@MetalRules,没错,这个并没有帮助。 - mate00
禁用帧头对我有用! - Mohamed Iqzas

7

使用Spring Boot 3,以下代码适用于我:

@Configuration 
class securityConfig {
    @Bean
    public WebSecurityCustomizer webSecurityCustomizer() {
        return (web) -> web.ignoring().requestMatchers(new AntPathRequestMatcher("/h2-console/**"));
    }
}

对我来说有效! - Nick Legend
对于那些认为可以忽略new AntPathRequestMatcher()的人 - 不要这样做。没有它似乎无法正常工作。 - Navneeth S

5

虽然排名最高的答案是正确的。

从现在起,WebSecurityConfigurerAdapter已被新版Spring Security废弃,而下一步操作是创建WebSecurityCustomizer Bean。在您的安全配置类中添加以下Bean即可解决问题。

@Bean
public WebSecurityCustomizer webSecurityCustomizer() {
    return (web) -> web.ignoring().antMatchers("/h2-console/**");
}

从2023年开始:您正在要求Spring Security忽略Mvc [pattern='/h2-console/**']。这并不推荐使用 - 请改用HttpSecurity#authorizeHttpRequests中的permitAll。 - maksimov

5

我希望能提供类似于 @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();
    }
}

实际上,在boot 1.3中进行了类似的配置,称为H2ConsoleSecurityConfiguration,但现在已经不存在了: 旧的类 Github讨论 更新:此处有非常重要的说明!当您有多个WebSecurityConfigurerAdapter时,它们可能会相互冲突,因此如果您的代码中有另一个WebSecurityConfigurerAdapter,则需要以某种方式将它们合并。要更详细地说明为什么会发生冲突,原因是每个适配器都设置了自己的过滤器链,并且每个请求都必须通过这两个过滤器链。如果其中一个链禁止frameOptions而另一个链没有,则请求将无法通过第一个链。因此,请注意使用多个配置器。

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

从Spring Boot的源代码中可以看出,如果您启用了基本配置,Spring Boot将使用顺序SecurityProperties.BASIC_AUTH_ORDER - 10加载Spring安全配置H2ConsoleSecurityConfigurer,认证基于您在安全性方面的配置。这是默认的安全配置:

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

    }

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” > “ROLE_USER”,但我需要更好地理解这个问题。
我已经更新了我的设置:
security:
  basic:
    enabled: true
    authorize-mode: NONE

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


你可以在我的答案中看到我的评论。 - chaoluo
这不会破坏授权吗? - AlikElzin-kilaka
授权已启用,因此如果用户没有被分配的角色,她将被拒绝访问。 - Tuhin Kanti Sharma

3
随着Spring Security 5.7.0-M2的发布,WebSecurityConfigurerAdapter已经被弃用。现在推荐使用HttpSecurity#authorizeHttpRequests中的permitAll来实现相同的功能,详见Spring博客。 您还需要禁用CSRF,但仅限于H2-console。然后允许来自页面同源的帧的X-Frame选项。 尽管仍不建议在生产中使用此方法,但通过这种方式,您可以在为站点启用CSRF的同时,继续测试安全性并访问H2-console。 更新至Spring Security 6。
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
    return http.authorizeHttpRequests()
            .requestMatchers(AntPathRequestMatcher.antMatcher("/h2-console/**")).permitAll()
            .and()
            .csrf().ignoringRequestMatchers(AntPathRequestMatcher.antMatcher("/h2-console/**"))
            .and()
            .headers(headers -> headers.frameOptions().sameOrigin())
            .build();
}

2

关于 WebSecurityConfigurerAdapter,我认为更恰当且解释得更好的答案在这里可找到。 虽然我已经添加了示例代码,并且对于h2控制台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);            
}

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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接