Spring Security认证成功后所有请求返回403 Forbidden问题
问题修复方案
1. 修正SecurityConfig的授权规则
核心问题在于授权规则配置错误,且角色权限前缀不匹配,先调整安全过滤链配置:
@Bean public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { http.csrf().disable() .authorizeHttpRequests() .requestMatchers(publicEndpoints()).permitAll() // 私有端点要求已登录用户访问,替换原permitAll配置 .requestMatchers(userEndpoints()).authenticated() .requestMatchers(adminEndpoints()).hasRole("ADMIN") // 其他请求默认要求认证(若有特定路径需拒绝,可单独配置) .anyRequest().authenticated() .and() .sessionManagement() .sessionCreationPolicy(SessionCreationPolicy.STATELESS) .and() .authenticationProvider(authProvider) .addFilterBefore(jwtAuthFilter, UsernamePasswordAuthenticationFilter.class) .exceptionHandling() .accessDeniedHandler((request, response, ex) -> { System.out.println("Access Denied: " + ex.getMessage()); response.sendError(HttpServletResponse.SC_FORBIDDEN); }); return http.build(); }
关键修改说明:
- 把
.requestMatchers(userEndpoints()).permitAll()改为.authenticated(),符合「仅已登录用户可访问私有端点」的需求 - 替换
.anyRequest().denyAll()为.authenticated(),避免误拦截未匹配到规则的合法请求
2. 确保角色权限前缀匹配
Spring Security中hasRole("USER")等价于hasAuthority("ROLE_USER"),如果你的UserDetails实现中给用户添加的权限是USER而非ROLE_USER,会导致权限校验失败返回403。
检查UserDetailsService实现,确保权限带ROLE_前缀:
// 示例:正确的权限设置方式 List<GrantedAuthority> authorities = Collections.singletonList( new SimpleGrantedAuthority("ROLE_USER") ); return new User(user.getUsername(), user.getPassword(), authorities);
若不想使用ROLE_前缀,可改用hasAuthority("USER")替代hasRole("USER")。
3. 验证JWT过滤器逻辑
确认JwtAuthenticationFilter的核心逻辑正常工作:
- 检查
jwtService.extractUsername(jwtToken)是否能正确解析用户名 - 检查
jwtService.isTokenValid(jwtToken, userDetails)是否正确验证token签名、过期时间及用户名匹配 - 确认
SecurityContextHolder.getContext().setAuthentication(authToken)代码被执行,且authToken包含正确的用户权限
4. 确保@PreAuthorize注解生效
若使用方法级权限注解@PreAuthorize("hasRole('USER')"),需确保@EnableMethodSecurity开启prePost支持(默认开启,可显式配置):
@EnableMethodSecurity(prePostEnabled = true) public class SecurityConfig { // ... 其他配置 }
同时注解中的权限字符串需与UserDetails中的权限保持一致(带ROLE_前缀)。
原现象原因解释
- 原配置中
.requestMatchers(userEndpoints()).permitAll()仍返回403:大概率是请求路径未匹配到/u/**,或JWT过滤器未正确设置认证信息,导致请求被.anyRequest().denyAll()直接拦截(此场景不会触发accessDeniedHandler,因此无日志) - 修改为
.hasRole("USER")后出现Access Denied日志:说明路径匹配成功,但用户的Authentication不包含ROLE_USER权限,触发权限校验失败
内容的提问来源于stack exchange,提问作者tgoel-dev
相关产品推荐
相关产品推荐

