You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.25 03:18:11