SpringBoot中使用SecurityFilterChain出现403禁止访问错误
Spring Security权限配置导致ADMIN端点返回403问题排查
问题说明
使用版本:Spring Boot 2.7.8、Spring Security core 6.1.0、spring-security-config 5.7.6、spring-security-web 5.7.6。当前SecurityFilterChain运行异常:配置permitAll()的GET请求可正常访问,但配置hasAuthority("ADMIN")的/admin系列端点返回Forbidden错误。
相关代码
SecurityConfig类
@Configuration @EnableWebSecurity @RequiredArgsConstructor public class SecurityConfig { private final JWTAuthFilter jwtAuthFilter; private final AuthenticationProvider authenticationProvider; private final LogoutHandler logoutHandler; private static final String AUTH_END_POINT = "/auth/**"; private static final String CATEGORY_ADMIN = "/categories/admin/**"; private static final String ORDER_ADMIN = "/orders/admin/**"; private static final String VENDOR_ADMIN = "/vendors/admin/**"; private static final String PRODUCT_ADMIN = "/products/admin/**"; private static final String USER_ADMIN = "/users/admin/**"; private static final String ADMIN = "ADMIN"; @Bean public SecurityFilterChain securityFilterChain(@NotNull HttpSecurity http) throws Exception { http .csrf() .disable() .authorizeRequests() .antMatchers(AUTH_END_POINT).permitAll() .antMatchers(HttpMethod.GET, "/vendors/**").permitAll() .antMatchers(HttpMethod.GET, "/categories/**").permitAll() .antMatchers(HttpMethod.GET, "/products/**").permitAll() .antMatchers(HttpMethod.GET, "/users/**").permitAll() .antMatchers(HttpMethod.GET, "/orders/**").permitAll() .antMatchers(PRODUCT_ADMIN).hasAuthority(ADMIN) .antMatchers(VENDOR_ADMIN).hasAuthority(ADMIN) .antMatchers(USER_ADMIN).hasAuthority(ADMIN) .antMatchers(CATEGORY_ADMIN).hasAuthority(ADMIN) .antMatchers(ORDER_ADMIN).hasAuthority(ADMIN) .anyRequest() .authenticated() .and() .sessionManagement() .sessionCreationPolicy(SessionCreationPolicy.STATELESS) .and() .authenticationProvider(authenticationProvider) .addFilterBefore(jwtAuthFilter, UsernamePasswordAuthenticationFilter.class) .logout() .logoutUrl("/auth/logout") .addLogoutHandler(logoutHandler) .logoutSuccessHandler((request, response, authentication) -> SecurityContextHolder.clearContext()); return http.build(); } }
JWTAuthFilter类的doFilterInternal方法
@Override protected void doFilterInternal( @NonNull HttpServletRequest request, @NonNull HttpServletResponse response, @NonNull FilterChain filterChain ) throws ServletException, IOException { final String authHeader = request.getHeader("Authorization"); final String jwt; final String userEmail; if (authHeader == null || !authHeader.startsWith("Bearer ")) { filterChain.doFilter(request, response); return; } jwt = authHeader.substring(7); userEmail = jwtTokenProvider.extractUsername(jwt); if (userEmail != null && SecurityContextHolder.getContext().getAuthentication() == null) { UserDetails userDetails = this.userDetailsService.loadUserByUsername(userEmail); var isTokenValid = tokenRepository.findByToken(jwt) .map(t -> !t.isExpired() && !t.isRevoked()) .orElse(false); if (jwtTokenProvider.isTokenValid(jwt, userDetails) && isTokenValid) { UsernamePasswordAuthenticationToken authToken = new UsernamePasswordAuthenticationToken( userDetails, null, userDetails.getAuthorities() ); authToken.setDetails( new WebAuthenticationDetailsSource().buildDetails(request) ); SecurityContextHolder.getContext().setAuthentication(authToken); } } filterChain.doFilter(request, response); }
排查与解决方向
权限名称精确匹配检查
- 确认
UserDetails实现类返回的权限集合中,是否包含精确的ADMIN字符串,而非带ROLE_前缀的ROLE_ADMIN。hasAuthority()是精确匹配,若实际权限是ROLE_ADMIN,则需要改为hasAuthority("ROLE_ADMIN"),或者改用hasRole("ADMIN")(该方法会自动添加ROLE_前缀)。 - 检查JWT令牌中存储的权限字段是否正确,确保
jwtTokenProvider解析出的权限与UserDetails中的一致。
- 确认
统一Spring Security版本
- 当前混用了Spring Security 6.1.0的core包和5.7.6的config、web包,版本不一致可能导致权限校验逻辑异常。建议将
spring-security-core版本改为5.7.6,与Spring Boot 2.7.x的依赖版本保持一致。
- 当前混用了Spring Security 6.1.0的core包和5.7.6的config、web包,版本不一致可能导致权限校验逻辑异常。建议将
调整请求匹配规则顺序
- 当前配置中,宽泛的
/users/**等GET请求规则排在/admin规则前面,会导致GET /users/admin/xxx这类请求被直接permitAll放行,但非GET请求的/admin端点会触发权限校验。若你遇到的是GET请求/admin端点返回403,可忽略此点;若为其他方法,需确保权限配置正确。如需让/admin规则优先匹配,可将/admin相关的antMatchers移到前面的permitAll规则之前。
- 当前配置中,宽泛的
验证JWT过滤器中的权限加载
- 在
JWTAuthFilter中添加日志,打印userDetails.getAuthorities()的内容,确认当前用户是否真的拥有ADMIN权限。例如:System.out.println("当前用户权限:" + userDetails.getAuthorities()); - 同时检查
tokenRepository中该JWT令牌是否存在、未过期且未被撤销,以及jwtTokenProvider.isTokenValid()方法是否正确验证了令牌有效性。
- 在
检查AuthenticationProvider配置
- 确认
authenticationProviderBean是否正确配置,比如DaoAuthenticationProvider是否正确关联了UserDetailsService和PasswordEncoder,确保认证过程中能正确加载用户的权限信息。
- 确认
内容的提问来源于stack exchange,提问作者Aida
相关产品推荐
相关产品推荐

