Spring Security 403 Forbidden异常排查:Spring Boot REST API权限问题
我仔细看了你的代码和调试信息,很快找到了导致403错误的核心原因,咱们一步步来解决:
1. 核心问题:权限字符串生成错误
在CustomUserDetails的getAuthorities()方法里,你直接把Role对象和"ROLE_"拼接了,而不是获取Role实体中存储角色名称的role字段值:
// 错误写法 return user.getRoles().stream().map(role -> new SimpleGrantedAuthority("ROLE_" + role)).collect(Collectors.toSet());
这样生成的权限字符串会是类似ROLE_Role(id=1, role=ADMIN)的格式,而Spring Security期望的是ROLE_ADMIN这种标准格式,自然无法匹配你配置的ADMIN角色,导致返回403。
修正后的代码
修改getAuthorities()方法,明确获取Role对象的role字段:
@Override public Collection<? extends GrantedAuthority> getAuthorities() { return user.getRoles().stream() .map(role -> new SimpleGrantedAuthority("ROLE_" + role.getRole())) .collect(Collectors.toSet()); }
2. 补充:给Role类添加getter方法
你的Role实体类中定义了private String role;字段,但没有提供对应的getRole()方法,上面的修正代码会编译报错。需要给Role类添加getter(建议同时加setter):
@Table(name = "Roles") public class Role { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Integer id; private String role; // 添加以下getter和setter public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getRole() { return role; } public void setRole(String role) { this.role = role; } }
3. 可选优化:简化Security配置
你的SecurityConfiguration里重复调用了authorizeRequests(),可以合并成更简洁的写法,功能完全一致:
@Override protected void configure(HttpSecurity http) throws Exception { http.csrf().disable() .httpBasic() .and() .authorizeRequests() .antMatchers("/rest/**").permitAll() .antMatchers("/secure/**").hasAnyRole("ADMIN") .anyRequest().authenticated() .and() .formLogin() .permitAll(); }
验证逻辑
修正后,用户登录时getAuthorities()会生成ROLE_ADMIN权限字符串,无论是你配置的antMatchers("/secure/**").hasAnyRole("ADMIN")还是Controller上的@PreAuthorize("hasAnyRole('ADMIN')"),都会正确匹配(因为hasAnyRole会自动给参数加上ROLE_前缀,实际检查的就是ROLE_ADMIN),这样就能正常访问需要ADMIN角色的接口了。
内容的提问来源于stack exchange,提问作者user9347049

