调用接口返回403 Forbidden,自定义认证Provider问题排查求助
排查接口返回403 Forbidden的问题
调用任意接口均返回403 Forbidden错误,为实现基于角色的认证,编写了CustomAuthenticationProvider及SecurityConfig配置类,相关代码如下:
CustomAuthenticationProvider 代码
@Component public class CustomAuthenticationProvider implements AuthenticationProvider { private final CustomerRepository customerRepository; private final PasswordEncoder passwordEncoder; public CustomAuthenticationProvider(CustomerRepository customerRepository, PasswordEncoder passwordEncoder) { this.customerRepository = customerRepository; this.passwordEncoder = passwordEncoder; } @Override public Authentication authenticate(Authentication authentication) throws AuthenticationException { Customer customer = customerRepository.findByEmail(authentication.getName()).orElseThrow(() -> new CustomerNotFoundException(authentication.getName())); if(passwordEncoder.matches(authentication.getCredentials().toString(), customer.getPwd())) { return new UsernamePasswordAuthenticationToken( customer.getEmail(), customer.getPwd(), getGrantedAuthorities(customer.getAuthorities())); } else{ throw new BadCredentialsException("Invalid Credentials"); } } private List<GrantedAuthority> getGrantedAuthorities(Set<Authority> authorities) { List<GrantedAuthority> grantedAuthorities = new ArrayList<>(); for (Authority authority : authorities) { grantedAuthorities.add(new SimpleGrantedAuthority(authority.getName())); } return grantedAuthorities; } @Override public boolean supports(Class<?> authentication) { return (UsernamePasswordAuthenticationToken.class.isAssignableFrom(authentication)); } }
SecurityConfig 代码
@Configuration public class SecurityConfig { @Bean SecurityFilterChain defaultSecurityFilterChain(HttpSecurity http) throws Exception { CsrfTokenRequestAttributeHandler requestHandler = new CsrfTokenRequestAttributeHandler(); requestHandler.setCsrfRequestAttributeName("_csrf"); http.securityContext((context) -> context.requireExplicitSave(false)) .sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.ALWAYS)) .cors(cors -> cors.configurationSource(new CorsConfigurationSource() { @Override public CorsConfiguration getCorsConfiguration(HttpServletRequest request) { CorsConfiguration config = new CorsConfiguration(); config.setAllowedOrigins(Collections.singletonList("http://localhost:4200")); config.setAllowedMethods(Collections.singletonList("*")); config.setAllowCredentials(true); config.setAllowedHeaders(Collections.singletonList("*")); config.setMaxAge(3600L); return config; } })).csrf((csrf) -> csrf .csrfTokenRequestHandler(requestHandler).ignoringRequestMatchers("/contact","/register") .csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse())) .addFilterAfter(new CSRFCookieFilter(), BasicAuthenticationFilter.class) .authorizeHttpRequests((requests)->requests .requestMatchers("/myAccount").hasRole("USER") .requestMatchers("/myBalance").hasAnyRole("USER","ADMIN") .requestMatchers("/myLoans").hasRole("USER") .requestMatchers("/myCards").hasRole("USER") .requestMatchers("/user").authenticated() .requestMatchers("/notices","/contact","/register").permitAll()) .formLogin(Customizer.withDefaults()) .httpBasic(Customizer.withDefaults()); return http.build(); } @Bean public PasswordEncoder getPasswordEncoder(){ return new BCryptPasswordEncoder(); } }
问题排查与修复方案
1. 权限前缀不匹配
Spring Security的hasRole()方法会自动为角色名添加ROLE_前缀,但你的getGrantedAuthorities方法直接将数据库中存储的角色名(如USER)作为权限标识,导致实际权限为USER,而hasRole("USER")会校验ROLE_USER,两者不匹配触发403。
修复方式二选一:
- 生成权限时添加前缀:
private List<GrantedAuthority> getGrantedAuthorities(Set<Authority> authorities) { List<GrantedAuthority> grantedAuthorities = new ArrayList<>(); for (Authority authority : authorities) { // 添加ROLE_前缀 grantedAuthorities.add(new SimpleGrantedAuthority("ROLE_" + authority.getName())); } return grantedAuthorities; } - 改用
hasAuthority()替代hasRole(),保持权限名一致:.authorizeHttpRequests((requests)->requests .requestMatchers("/myAccount").hasAuthority("USER") .requestMatchers("/myBalance").hasAnyAuthority("USER","ADMIN") .requestMatchers("/myLoans").hasAuthority("USER") .requestMatchers("/myCards").hasAuthority("USER") // 其余规则不变 )
2. 自定义AuthenticationProvider未注册
你的SecurityConfig中没有将CustomAuthenticationProvider注册到Spring Security的认证流程中,导致默认认证逻辑未被替换,认证后可能没有正确赋予角色权限。
修复方式:
在SecurityConfig中注入自定义Provider并配置到HttpSecurity:
@Autowired private CustomAuthenticationProvider customAuthenticationProvider; @Bean SecurityFilterChain defaultSecurityFilterChain(HttpSecurity http) throws Exception { // 原有代码... // 添加这行注册自定义Provider http.authenticationProvider(customAuthenticationProvider); // 原有代码... }
3. 认证Token的Principal信息不完整
当前返回的UsernamePasswordAuthenticationToken使用customer.getEmail()作为principal,若后续业务逻辑需要获取用户的角色或其他信息,可能无法正确获取。建议直接传入Customer对象,让SecurityContext持有完整的用户信息:
修复方式:
return new UsernamePasswordAuthenticationToken( customer, // 替换为customer对象 customer.getPwd(), getGrantedAuthorities(customer.getAuthorities()) );
内容的提问来源于stack exchange,提问作者Avnish Shrivastava
相关产品推荐
相关产品推荐

