Spring Security配置Quartz Manager的一次异常

问题描述:

Spring Security的配置如下,期望对/quartz-manager-ui/路径下的所有资源进行httpBasic和formLogin认证

    @Bean
    @Order(1)
    public SecurityFilterChain formSecurityFilterChain(HttpSecurity http) {

        try {
            return http
                    .csrf(AbstractHttpConfigurer::disable)
                    .cors(AbstractHttpConfigurer::disable)
                    //.securityMatcher("/druid/**", "/login")
                    .securityMatchers((config) -> config
                            .requestMatchers(
                                    AntPathRequestMatcher.antMatcher("/druid/**"),
                                    AntPathRequestMatcher.antMatcher("/login"),
                                    AntPathRequestMatcher.antMatcher("/doc.html/**"),
                                    AntPathRequestMatcher.antMatcher("/v3/api-docs/**"),
                                    AntPathRequestMatcher.antMatcher("/webjars/**"),
                                    AntPathRequestMatcher.antMatcher("/swagger*/**"),
                                    AntPathRequestMatcher.antMatcher("/default-ui.css"),
                                    AntPathRequestMatcher.antMatcher("/quartz-manager-ui/**")
                                    ))
                    .authorizeHttpRequests((config) -> {
                       config.anyRequest().authenticated();
                    })
                    .httpBasic((configurer) -> {})
                    .formLogin(Customizer.withDefaults())
                    .build();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }

    }

以上配置的实际效果:
在第一次登录时(即cookie中的JSESSION没有任何信息时),可以正常登录,但是进入后页面出现404:
image
之后所有的请求都会出现403 code,这是什么原因呢?

原因:

  1. 这个页面上有部分接口非/quartz-manager-ui/开头,例如:/quartz-manager/auth/whoami
  2. 项目中还配置了另外一个SecurityFilterChain,/quartz-manager/auth/whoami接口没有走上面配置的SecurityFilterChain,从而导致该接口认证失败,且返回了认证失败信息:
    image
  3. 在Spring Security的流程中,认证失败会情况SecurityContext中的信息,也即会清除第一次表单登录后的用户信息,所以导致了之后的接口都出现了403错误,代码如下:
    org.springframework.security.web.access.ExceptionTranslationFilter#sendStartAuthentication
    protected void sendStartAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain,
    		AuthenticationException reason) throws ServletException, IOException {
    	// SEC-112: Clear the SecurityContextHolder's Authentication, as the
    	// existing Authentication is no longer considered valid
    	SecurityContext context = this.securityContextHolderStrategy.createEmptyContext();
    	//情况登录信息
    	this.securityContextHolderStrategy.setContext(context);
    	this.requestCache.saveRequest(request, response);
    	this.authenticationEntryPoint.commence(request, response, reason);
    }
    

解决方案:

在SecurityFilterChain添加/quartz-manager/**路径匹配

    @Bean
    @Order(1)
    public SecurityFilterChain formSecurityFilterChain(HttpSecurity http) {

        try {
            return http
                    .csrf(AbstractHttpConfigurer::disable)
                    .cors(AbstractHttpConfigurer::disable)
                    //.securityMatcher("/druid/**", "/login")
                    .securityMatchers((config) -> config
                            .requestMatchers(
                                    AntPathRequestMatcher.antMatcher("/druid/**"),
                                    AntPathRequestMatcher.antMatcher("/login"),
                                    AntPathRequestMatcher.antMatcher("/doc.html/**"),
                                    AntPathRequestMatcher.antMatcher("/v3/api-docs/**"),
                                    AntPathRequestMatcher.antMatcher("/webjars/**"),
                                    AntPathRequestMatcher.antMatcher("/swagger*/**"),
                                    AntPathRequestMatcher.antMatcher("/default-ui.css"),
                                    AntPathRequestMatcher.antMatcher("/quartz-manager-ui/**"),
                                    AntPathRequestMatcher.antMatcher("/quartz-manager/**")

                                    ))
                    .authorizeHttpRequests((config) -> {
                       config.anyRequest().authenticated();
                    })
                    .httpBasic((configurer) -> {})
                    .formLogin(Customizer.withDefaults())
                    .build();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }

    }
posted @ 2025-07-18 10:13  Hekk丶  阅读(19)  评论(0)    收藏  举报