SpringBoot3自定义过滤器场景下SecurityConfig失效问题求助
问题:SpringBoot3中Security自定义过滤器导致/h2-console权限配置失效
问题描述
已为/h2-console/**路径设置permitAll权限,但访问该路径时仍会进入配置的CustomAuthenticationEntryPoint。尝试配置AnonymousAuthenticationFilter也未生效。
相关配置代码
SecurityConfig
@Bean protected SecurityFilterChain filterChain(HttpSecurity http) throws Exception{ return http .httpBasic().disable() .formLogin().disable() .csrf().disable() .headers().frameOptions().disable() .and() .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS) .and() .authorizeHttpRequests( authorize -> { try { authorize .requestMatchers("/h2-console/**").permitAll() .requestMatchers("/exception/**").permitAll() .requestMatchers(HttpMethod.POST, "/api/sign-in", "/api/sign-up", "/api/refresh-token").permitAll() .requestMatchers(HttpMethod.GET, "/api/**").permitAll() .requestMatchers(HttpMethod.DELETE, "/api/members/{id}/**") .access((authentication, object) -> { String idAttr = object.getVariables().get("id"); return new AuthorizationDecision(memberGuard.check(Long.parseLong(idAttr))); }) .requestMatchers(HttpMethod.GET, "/swagger-ui.html/**", "/v3/api-docs/**", "/swagger-ui/**", "/swagger-resources/**").permitAll() .anyRequest().hasRole("ADMIN"); }catch (Exception e){ e.printStackTrace(); } }) .exceptionHandling().accessDeniedHandler(new CustomAccessDeniedHandler()) .and() .exceptionHandling().authenticationEntryPoint(new CustomAuthenticationEntryPoint()) .and() .addFilterBefore(new JwtAuthenticationFilter(accessTokenHelper, userDetailsService), UsernamePasswordAuthenticationFilter.class) .build(); }
自定义JwtAuthenticationFilter
@RequiredArgsConstructor @Slf4j public class JwtAuthenticationFilter extends OncePerRequestFilter { private final TokenHelper accessTokenHelper; private final CustomUserDetailsService userDetailsService; @Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { String token = extractToken(request); if(validateToken(token)) { setAuthentication(token); } filterChain.doFilter(request, response); } private String extractToken(HttpServletRequest request) { return request.getHeader("Authorization"); } private boolean validateToken(String token) { return token != null && accessTokenHelper.validate(token); } private void setAuthentication(String token) { String userId = accessTokenHelper.extractSubject(token); CustomUserDetails userDetails = userDetailsService.loadUserByUsername(userId); SecurityContextHolder.getContext().setAuthentication(new CustomAuthenticationToken(userDetails, userDetails.getAuthorities())); } }
CustomUserDetailsService
@Component @Transactional(readOnly = true) @RequiredArgsConstructor public class CustomUserDetailsService implements UserDetailsService { private final MemberRepository memberRepository; @Override public CustomUserDetails loadUserByUsername(String userId) throws UsernameNotFoundException { Member member = memberRepository.findById(Long.valueOf(userId)) .orElseGet(Member::anonymousMember); return new CustomUserDetails( String.valueOf(member.getId()), member.getRoleSet().stream().map(MemberRole::getAuthority) .map(SimpleGrantedAuthority::new).collect(Collectors.toSet())); } }
尝试过的无效配置
.anonymous().authenticationFilter(new AnonymousAuthenticationFilter("key", "anonymousUser", AuthorityUtils.createAuthorityList("ROLE_ANONYMOUS")))
问题原因
- 全局try-catch破坏权限配置逻辑:在
authorizeHttpRequests的lambda中包裹全局try-catch,若配置过程中抛出异常(如ID转换失败),会导致权限规则配置不完整,可能使permitAll规则失效,所有请求默认走anyRequest().hasRole("ADMIN"),触发认证入口。 - Jwt过滤器未跳过免校验路径:自定义Jwt过滤器会处理所有请求,包括
permitAll路径,若请求无有效Token,SecurityContext会保持为空,后续匿名认证逻辑可能因顺序问题无法正常触发。 - 手动配置AnonymousAuthenticationFilter干扰默认逻辑:STATELESS模式下Spring Security默认会启用匿名认证,手动配置可能因参数不匹配导致失效。
解决方案
1. 移除全局try-catch,局部处理异常
将权限配置中的异常处理移到access逻辑内部,避免破坏整个权限规则的构建:
.authorizeHttpRequests(authorize -> authorize .requestMatchers("/h2-console/**").permitAll() .requestMatchers("/exception/**").permitAll() .requestMatchers(HttpMethod.POST, "/api/sign-in", "/api/sign-up", "/api/refresh-token").permitAll() .requestMatchers(HttpMethod.GET, "/api/**").permitAll() .requestMatchers(HttpMethod.DELETE, "/api/members/{id}/**") .access((authentication, object) -> { try { String idAttr = object.getVariables().get("id"); return new AuthorizationDecision(memberGuard.check(Long.parseLong(idAttr))); } catch (NumberFormatException e) { return new AuthorizationDecision(false); } }) .requestMatchers(HttpMethod.GET, "/swagger-ui.html/**", "/v3/api-docs/**", "/swagger-ui/**", "/swagger-resources/**").permitAll() .anyRequest().hasRole("ADMIN") )
2. 让Jwt过滤器跳过免校验路径
重写shouldNotFilter方法,排除所有permitAll的路径:
@Override protected boolean shouldNotFilter(HttpServletRequest request) throws ServletException { String path = request.getRequestURI(); String method = request.getMethod(); return path.startsWith("/h2-console/") || path.startsWith("/exception/") || (HttpMethod.POST.name().equals(method) && (path.equals("/api/sign-in") || path.equals("/api/sign-up") || path.equals("/api/refresh-token"))) || (HttpMethod.GET.name().equals(method) && path.startsWith("/api/")) || path.startsWith("/swagger-ui.html/") || path.startsWith("/v3/api-docs/") || path.startsWith("/swagger-ui/") || path.startsWith("/swagger-resources/"); }
3. 移除手动配置的AnonymousAuthenticationFilter
STATELESS模式下Spring Security会自动启用匿名认证,无需手动配置,移除相关代码即可恢复默认逻辑。
4. 合并exceptionHandling配置
避免重复调用exceptionHandling(),简化配置:
.exceptionHandling() .accessDeniedHandler(new CustomAccessDeniedHandler()) .authenticationEntryPoint(new CustomAuthenticationEntryPoint())
验证步骤
- 按上述修改权限配置和Jwt过滤器代码
- 移除手动配置的匿名过滤器
- 重启服务后访问
/h2-console,应能正常进入且不会触发CustomAuthenticationEntryPoint
内容的提问来源于stack exchange,提问作者bc a
相关产品推荐
相关产品推荐

