Spring Security基于角色授权问题:403禁止访问错误排查
你的403错误主要来自三个核心问题:权限字符串不匹配、OAuth2 JWT认证与自定义UserDetails整合缺失、过滤器配置逻辑问题,以下是具体排查和修复步骤:
1. 权限字符串不匹配
你的CustomUserDetails在getAuthorities()方法中给角色添加了ROLE_前缀(例如角色名USER会被转换为ROLE_USER),但在SecurityFilterChain中使用hasAuthority("USER")进行权限校验,两者完全不匹配。
修复方案二选一:
- 直接使用完整权限字符串匹配:
.requestMatchers("/secret/**").hasAuthority("ROLE_USER") - 改用
hasRole方法(Spring Security会自动为角色名添加ROLE_前缀):.requestMatchers("/secret/**").hasRole("USER")
2. OAuth2资源服务器与CustomUserDetails的整合缺失
你配置了JWT类型的OAuth2资源服务器,但默认情况下Spring Security不会自动关联你的CustomUserDetails,导致认证流程中无法正确加载用户的权限信息。
场景A:从JWT直接解析权限
如果你的JWT payload中已经包含角色字段(例如roles: ["USER"]),需要自定义JwtAuthenticationConverter来正确转换权限:
@Bean public JwtAuthenticationConverter jwtAuthenticationConverter() { JwtGrantedAuthoritiesConverter authoritiesConverter = new JwtGrantedAuthoritiesConverter(); authoritiesConverter.setAuthorityPrefix("ROLE_"); // 匹配你UserDetails中的前缀 authoritiesConverter.setAuthoritiesClaimName("roles"); // 指定JWT中存储角色的字段名 JwtAuthenticationConverter converter = new JwtAuthenticationConverter(); converter.setJwtGrantedAuthoritiesConverter(authoritiesConverter); return converter; }
然后在SecurityFilterChain中关联:
.oauth2ResourceServer(oauth2 -> oauth2.jwt(jwt -> jwt.jwtAuthenticationConverter(jwtAuthenticationConverter())))
场景B:从数据库加载UserDetails
如果需要从数据库获取用户完整信息(而非仅从JWT解析),需要自定义JwtAuthenticationProvider来整合UserDetailsService:
@Bean public JwtAuthenticationProvider jwtAuthenticationProvider(JwtDecoder jwtDecoder, UserDetailsService userDetailsService) { JwtAuthenticationProvider provider = new JwtAuthenticationProvider(jwtDecoder); provider.setJwtAuthenticationConverter(jwt -> { String username = jwt.getSubject(); // 加载自定义UserDetails UserDetails userDetails = userDetailsService.loadUserByUsername(username); return new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities()); }); return provider; }
3. 过滤器配置逻辑问题
你使用addFilterBefore(authorizeFilter, UsernamePasswordAuthenticationFilter.class),但在无状态JWT认证场景下,UsernamePasswordAuthenticationFilter并不参与流程,这会导致自定义过滤器的执行顺序错误。
修复建议:
将自定义过滤器放在JwtAuthenticationTokenFilter之前(如果使用Spring Security默认的JWT过滤器),或者明确指定过滤器顺序:
.addFilterBefore(authorizeFilter, JwtAuthenticationTokenFilter.class)
同时必须确保你的authorizeFilter逻辑正确:
- 正确解析请求头中的JWT token
- 验证token合法性
- 将生成的
Authentication对象存入SecurityContextHolder
额外检查点
- 验证请求
/secret/**时是否携带了有效的JWT token,且token中的角色信息与你配置的权限匹配 - 确认
CustomUserDetails的其他方法(如isAccountNonExpired()、isEnabled()等)都返回true,避免因用户状态导致的403
内容的提问来源于stack exchange,提问作者Mészáros Benedek

