Spring Security 中访问 h2-console 小记

in OS with 0 comment

2023-02-13T09:58:54.png

在学习 Spring Boot 框架中,引入了 Spring Security 来安全验证,数据库层面使用了 Mybatis + H2。

由于之前没怎么接触过 H2(使用的目的主要是为了测试方便,本地也不需要单独安装一个 MySQL 等外部数据库),本着学习的心态,开始搞了起来。

项目在加入 Spring Security 后,开启运行,就会受到访问限制(401)。需要我们单独设置一下 SecurityFilterChain 来过滤掉一些不需要鉴权的 URL。于是添加下面的配置。

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
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.oauth2.server.resource.web.BearerTokenAuthenticationEntryPoint;
import org.springframework.security.oauth2.server.resource.web.access.BearerTokenAccessDeniedHandler;
import org.springframework.security.web.SecurityFilterChain;

@Configuration
@EnableWebSecurity
public class SecurityConfig {
    private static final String[] WHITE_LIST_URLS = {
            "/api-docs/**",
            "/swagger-ui.html",
            "/swagger-ui/**",
            "/v3/**",
            "/actuator/**",
            "/api/auth/**",
            "/h2-console/**"
    };

    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        http
                .cors()
                .and()
                .csrf().disable()
                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                .and()
                .authorizeHttpRequests(auth -> auth
                        .requestMatchers(HttpMethod.OPTIONS, "/**").permitAll()
                        .requestMatchers(WHITE_LIST_URLS).permitAll()
                        .anyRequest().authenticated()
                )
                .oauth2ResourceServer(OAuth2ResourceServerConfigurer::jwt)
                .exceptionHandling(exceptions -> exceptions
                        .authenticationEntryPoint(new BearerTokenAuthenticationEntryPoint())
                        .accessDeniedHandler(new BearerTokenAccessDeniedHandler())
                );

        return http.build();
    }
}

兴高采烈的运行起项目,结果死活访问不了 h2-console,在 application.yaml 中也开户了访问,也使不好使,网上的 demo 基本都试了一遍,最后无奈搜索一下 "h2-console spring boot 3.0.2",第一条为 Stackoverflow 的问题,看了一下,这不就是我苦苦追寻的嘛。

java - How can I access the H2-console while using Spring Security (Spring Boot 3.0.2)? - Stack Overflow

主要的原因是,如果心字符串数组形式传入 requestMatchers 将被 MvcRequestMatcher 处理,但 h2-console 不是 DispatcherServlet 的一部分。

综合解决方案如下:

在 application.yaml 文件中启用 h2-console,配置如下:

spring:
  application:
    name: jwt-mybatis-demo
  datasource:
    url: jdbc:h2:mem:jm
    driver-class-name: org.h2.Driver
  sql:
    init:
      data-locations: classpath:db/data.sql
      schema-locations: classpath:db/schema.sql
      mode: always
  h2:
    console:
      enabled: true

修改 SecurityConfig 文件如下,添加 WebSecurityCustomizer,单独处理一下 h2-console 的安全。

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
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.configuration.WebSecurityCustomizer;
import org.springframework.security.config.annotation.web.configurers.oauth2.server.resource.OAuth2ResourceServerConfigurer;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.oauth2.server.resource.web.BearerTokenAuthenticationEntryPoint;
import org.springframework.security.oauth2.server.resource.web.access.BearerTokenAccessDeniedHandler;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;

@Configuration
@EnableWebSecurity
public class SecurityConfig {
    private static final String[] WHITE_LIST_URLS = {
            "/api-docs/**",
            "/swagger-ui.html",
            "/swagger-ui/**",
            "/v3/**",
            "/actuator/**",
            "/api/auth/**"
    };

    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        http
                .cors()
                .and()
                .csrf().disable()
                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                .and()
                .authorizeHttpRequests(auth -> auth
                        .requestMatchers(HttpMethod.OPTIONS, "/**").permitAll()
                        .requestMatchers(WHITE_LIST_URLS).permitAll()
                        .anyRequest().authenticated()
                )
                .oauth2ResourceServer(OAuth2ResourceServerConfigurer::jwt)
                .exceptionHandling(exceptions -> exceptions
                        .authenticationEntryPoint(new BearerTokenAuthenticationEntryPoint())
                        .accessDeniedHandler(new BearerTokenAccessDeniedHandler())
                );

        return http.build();
    }

    @Bean
    WebSecurityCustomizer webSecurityCustomizer() {
        // 单独处理一下 h2-console 如果放在 WHITE_LIST_URLS 中将不起作用 原因是上面的过滤走的是 MvcRequestMatcher 匹配器
        // 而 h2-console 不属于 DispatcherServlet 的一部分
        // reference: https://stackoverflow.com/questions/75367159/how-can-i-access-the-h2-console-while-using-spring-security-spring-boot-3-0-2/75367690
        return web -> web.ignoring()
                .requestMatchers(new AntPathRequestMatcher("/h2-console/**"));
    }
}
Comments are closed.