Spring Security设置AuthenticationManager父级未生效返回403如何解决
问题原因及解决方案
你的配置存在以下4处核心问题,直接导致请求返回403:
1. 自定义AuthenticationProvider逻辑错误
你的CustomProvider中authenticate方法写法完全不符合规范:
- 该方法要求返回值为
Authentication类型,你直接返回BadCredentialsException(异常类型)会直接触发类型转换错误,导致认证流程中断 - 认证失败时应该抛出
BadCredentialsException而不是返回,若需要让后续Provider/父级AuthenticationManager处理当前认证请求,应该返回null
2. 自定义Provider拦截了所有认证请求,父级永远不会触发
你给CustomProvider的supports方法返回了true,代表该Provider支持所有类型的认证请求,结合你当前错误的实现,所有请求走到该Provider就直接失败,根本不会触发你配置的父级global认证管理器。
3. 未配置认证入口,Postman请求无法传递认证信息
你的HttpSecurity配置中只声明了接口需要认证,但没有配置任何认证方式(比如表单登录、HTTP Basic认证),你用Postman发起请求时无法传递账号密码参数,自然会被判定为未认证返回403。
4. 路径匹配规则限制
你用antMatcher("/hello")指定了当前安全配置仅对/hello路径生效,如果你请求的是其他路径,会触发Spring Security默认的拦截规则,同样返回403。
修复代码示例
修正后的CustomProvider
@Component public class CustomProvider implements AuthenticationProvider { @Override public Authentication authenticate(Authentication authentication) throws AuthenticationException { // 示例逻辑:只有用户名是test的才走当前Provider处理,其他都返回null交给父级处理 String username = authentication.getName(); if ("test".equals(username)) { // 认证失败直接抛出异常 throw new BadCredentialsException("test用户禁止登录"); } // 返回null代表当前Provider不处理该请求,交给后续Provider/父级处理 return null; } @Override public boolean supports(Class<?> authentication) { // 这里只支持用户名密码认证类型,避免拦截其他认证请求 return UsernamePasswordAuthenticationToken.class.isAssignableFrom(authentication); } }
修正后的Security配置
@Configuration @EnableWebSecurity public class ProjectConfig extends WebSecurityConfigurerAdapter { @Autowired AuthenticationProvider authenticationProvider; @Bean public UserDetailsService userDetailsService() { // 更规范的全局用户配置方式,避免直接操作AuthenticationManagerBuilder导致的上下文冲突 UserDetails admin = User.withUsername("admin") .password("123") .authorities("ADMIN") .passwordEncoder(p -> NoOpPasswordEncoder.getInstance().encode(p)) .build(); return new InMemoryUserDetailsManager(admin); } @Override protected void configure(HttpSecurity http) throws Exception { http .antMatcher("/hello") .authorizeRequests() .anyRequest() .authenticated() // 开启HTTP Basic认证,方便Postman测试 .and() .httpBasic() // 测试时可以关闭csrf避免Postman请求被拦截 .and() .csrf().disable(); } @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { auth.authenticationProvider(authenticationProvider); // 父级直接使用全局配置的AuthenticationManager即可 auth.parentAuthenticationManager(authenticationManagerBean()); } }
测试说明
修复后用Postman请求/hello接口,选择Authorization类型为Basic Auth,填入用户名admin、密码123即可正常访问,填入用户名test会返回认证失败错误,符合父级AuthenticationManager fallback的预期逻辑。
内容的提问来源于stack exchange,提问作者Wang hua
相关产品推荐
相关产品推荐

