Spring Security 6自定义Authentication Provider配置后403问题解决
Spring Security 6自定义请求头签名认证403问题解决
问题根源
你的代码触发403错误主要有三个核心原因:
- 过滤器调用
customAuthenticationProvider.authenticate()后,未将认证成功的Authentication对象存入SecurityContextHolder,Spring Security无法识别当前请求已通过认证。 - 认证返回的
GrantedAuthority为空集合,Spring Security默认授权规则要求用户至少拥有一个权限才能访问受保护资源。 CustomAuthenticationProvider的supports方法直接返回true过于宽泛,可能处理无关认证类型,存在潜在风险。
解决方案
1. 修改过滤器,保存认证结果到SecurityContext
在EverybodyAuthenticationFilter中,必须将认证成功的对象存入SecurityContext,让Spring Security识别当前用户:
@Component public class EverybodyAuthenticationFilter extends OncePerRequestFilter { @Autowired private CustomAuthenticationProvider customAuthenticationProvider; @Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { SecurityContext context = SecurityContextHolder.createEmptyContext(); // 执行认证并获取结果 Authentication authentication = customAuthenticationProvider.authenticate( new UsernamePasswordAuthenticationToken("admin", "system") ); // 将认证结果存入SecurityContext context.setAuthentication(authentication); SecurityContextHolder.setContext(context); filterChain.doFilter(request, response); } }
2. 为用户添加权限,优化AuthenticationProvider
给认证用户添加至少一个权限(比如ROLE_USER),同时限制supports方法只处理指定认证类型:
@Component public class CustomAuthenticationProvider implements AuthenticationProvider { @Override public Authentication authenticate(final Authentication authentication) throws AuthenticationException { final String name = authentication.getName(); final String password = authentication.getCredentials().toString(); if (!"admin".equals(name) || !"system".equals(password)) { throw new BadCredentialsException("用户名或密码错误"); } return authenticateAgainstThirdPartyAndGetAuthentication(name, password); } @Override public boolean supports(Class<?> authentication) { // 仅支持UsernamePasswordAuthenticationToken类型 return UsernamePasswordAuthenticationToken.class.isAssignableFrom(authentication); } private static UsernamePasswordAuthenticationToken authenticateAgainstThirdPartyAndGetAuthentication(String name, String password) { // 添加基础权限,满足Spring Security授权要求 final List<GrantedAuthority> grantedAuths = List.of(new SimpleGrantedAuthority("ROLE_USER")); final UserDetails principal = new User(name, password, grantedAuths); return new UsernamePasswordAuthenticationToken(principal, password, grantedAuths); } }
3. 简化SecurityConfig配置(可选)
Spring Security 6支持更简洁的Provider注册方式,无需手动构建AuthenticationManager:
@EnableWebSecurity @Configuration @ComponentScan("com.example.demo") public class SecurityConfig { @Autowired private CustomAuthenticationProvider authProvider; @Bean public SecurityFilterChain filterChain(HttpSecurity http, EverybodyAuthenticationFilter everyFilter) throws Exception { return http .authorizeHttpRequests(auth -> auth.anyRequest().authenticated()) .authenticationProvider(authProvider) // 直接注册自定义Provider .addFilterBefore(everyFilter, BasicAuthenticationFilter.class) .build(); } }
验证说明
修改完成后,过滤器会将认证用户信息存入SecurityContext,同时用户拥有ROLE_USER权限,Spring Security会识别请求已通过认证,允许访问/home接口。后续可将硬编码的用户名密码替换为从请求头提取的签名信息,完成基于请求头的自定义认证逻辑。
内容的提问来源于stack exchange,提问作者Viraj
相关产品推荐
相关产品推荐

