自定义Spring Security过滤器测试返回401如何解决?
问题排查与解决方案
1. 检查自定义过滤器的认证Token有效性
你的示例过滤器中使用UsernamePasswordAuthenticationToken的三参数构造器,理论上会标记为已认证,但如果实际过滤器未正确设置认证状态或权限,会导致后续授权失败:
- 确保校验通过时,创建的
Authentication对象满足:- 使用三参数构造器(
principal, credentials, authorities),此时isAuthenticated()会返回true - 权限集合即使为空,也需传入空集合而非
null
// 正确示例 Collection<GrantedAuthority> authorities = Collections.emptyList(); UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken("principal@springboot.com", null, authorities); - 使用三参数构造器(
2. 修正MockMVC请求头的类型错误
HTTP请求头的值必须是字符串,测试中传递整数类型的companyId会导致过滤器无法正确解析参数,触发校验失败:
// 修改前 .header("companyId", 1438) // 修改后 .header("companyId", "1438")
3. 确保过滤器与安全配置在测试环境中被加载
- 检查
TestApplication的组件扫描范围是否包含WebSecurityConfig和AuthGatewayFilter,若测试用TestApplication是独立配置,需显式导入:@SpringBootApplication(scanBasePackageClasses = {WebSecurityConfig.class, AuthGatewayFilter.class}) public class TestApplication { /* ... */ } - 或在测试类中直接指定加载的配置类:
@SpringBootTest(classes = {WebSecurityConfig.class, AuthGatewayFilter.class, TestApplication.class})
4. 验证过滤器是否被正确执行
在AuthGatewayFilter的doFilterInternal方法中添加日志,确认测试时过滤器是否触发:
@Override protected void doFilterInternal(...) throws ServletException, IOException { log.info("AuthGatewayFilter processing request: {}", request.getRequestURI()); // 原有逻辑... }
若日志未输出,说明安全配置未被正确加载,需检查@EnableWebSecurity和SecurityFilterChain的注册是否生效。
5. 显式配置MockMVC启用Spring Security支持
虽然@AutoConfigureMockMvc默认集成Spring Security,但手动配置可确保安全过滤器链被正确应用:
@Autowired private WebApplicationContext context; private MockMvc mockMvc; @BeforeEach void setUp() { mockMvc = MockMvcBuilders.webAppContextSetup(context) .apply(springSecurity()) // 显式启用Spring Security支持 .build(); }
6. Mock过滤器逻辑(用于单元测试)
如果不想依赖真实的JWT校验逻辑,可在测试中替换AuthGatewayFilter为Mock实现:
@SpringBootTest @ContextConfiguration(classes = TestApplication.class) @AutoConfigureMockMvc class Auth0IntegrationControllerTest { @MockBean private AuthGatewayFilter authGatewayFilter; @Autowired MockMvc mockMvc; @BeforeEach void setUp() throws Exception { // Mock过滤器逻辑,直接设置认证 doAnswer(invocation -> { HttpServletRequest request = invocation.getArgument(0); UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken("principal@springboot.com", null, Collections.emptyList()); authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request)); SecurityContextHolder.getContext().setAuthentication(authentication); FilterChain chain = invocation.getArgument(2); chain.doFilter(request, invocation.getArgument(1)); return null; }).when(authGatewayFilter).doFilterInternal(any(), any(), any()); } // 测试方法... }
内容的提问来源于stack exchange,提问作者Lorenzo De Francesco
相关产品推荐
相关产品推荐

