Spring Boot 安全性中的 HTTP 403 禁止错误
Posted
技术标签:
【中文标题】Spring Boot 安全性中的 HTTP 403 禁止错误【英文标题】:HTTP 403 forbidden error in spring boot security 【发布时间】:2020-01-17 22:59:28 【问题描述】:Spring 安全配置类
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter
@Autowired
private UserDetailsService userDetailsService;
@Bean
public PasswordEncoder getPasswordEncoder()
return new BCryptPasswordEncoder();
@Override
protected void configure(HttpSecurity http) throws Exception
http
.cors()
.and()
.authorizeRequests()
.antMatchers("/user", "/login").permitAll()
.antMatchers("/employee", "/insurance").hasRole("User")
.anyRequest()
.authenticated()
.and()
.httpBasic()
.and()
.csrf().disable();
protected void configureGlobal(AuthenticationManagerBuilder auth) throws Exception
auth.userDetailsService(userDetailsService).passwordEncoder(getPasswordEncoder());
UserDetailsService 实现类
@Service
public class UserDetailsServiceImpl implements UserDetailsService
@Autowired
private UserService userService;
@Override
public UserDetails loadUserByUsername(String userName) throws UsernameNotFoundException
User user = null;
Set<GrantedAuthority> grantedAuthorities = null;
try
user = userService.findByUserName(userName);
if(user == null)
throw new UsernameNotFoundException("User " + userName + " not available");
grantedAuthorities = new HashSet<>();
for(Role role: user.getRoles())
grantedAuthorities.add(new SimpleGrantedAuthority(role.getRole().toString()));
catch(Exception exp)
exp.printStackTrace();
return new org.springframework.security.core.userdetails.User(user.getUserName(), user.getPassword(), grantedAuthorities);
员工休息控制器类
@RestController
public class EmployeeController
@Autowired
private EmployeeService employeeService;
@Autowired
private InsuranceService insuranceService;
@PostMapping("/employee")
public ResponseEntity<Employee> create(@RequestBody Employee employee) throws Exception
employee = employeeService.create(employee);
return new ResponseEntity<Employee>(employee, HttpStatus.CREATED);
@PutMapping("/employee")
public ResponseEntity<Employee> update(@RequestBody Employee employee) throws Exception
employee = employeeService.update(employee);
return new ResponseEntity<Employee>(employee, HttpStatus.OK);
@DeleteMapping("/employee/id")
public ResponseEntity<String> delete(@PathVariable("id") long id) throws Exception
employeeService.delete(id);
return new ResponseEntity<String>("Employee deleted successfully", HttpStatus.OK);
@GetMapping("/employee/id")
public ResponseEntity<Employee> findEmployeeDetails(@PathVariable("id") long id) throws Exception
Employee employee = employeeService.findById(id);
return new ResponseEntity<Employee>(employee, HttpStatus.OK);
@GetMapping("/employee")
public ResponseEntity<List<Employee>> findAll() throws Exception
List<Employee> employees = employeeService.findAll();
return new ResponseEntity<List<Employee>>(employees, HttpStatus.OK);
对于通过邮递员提交到 /employee URL 的任何 HTTP 方法(POST/GET/PUT)请求,我收到 403 禁止错误
"timestamp": "2019-09-17T05:37:35.778+0000",
"status": 403,
"error": "Forbidden",
"message": "Forbidden",
"path": "/hr-core/employee"
即使我在 POSTMAN 中的 HTTP 请求的基本身份验证标头(授权)中发送正确的用户名和密码,我也会收到此错误。该用户同时拥有 USER 和 ADMIN 角色来访问 /employee REST 端点。我在 http 安全中禁用了 CSRF。
我该如何解决这个错误?
【问题讨论】:
为什么路径是 /hr-core/employe 而不是 /employee? hr-core 是 Web 应用程序的上下文根。我正在解雇这个 - localhost:8083/hr-core/employee 邮递员中的 URL .antMatchers("/employee", "/insurance").hasRole("User") ____________ ...删除此行并尝试 @harkeshkumar 我希望 /employee url 进行身份验证。删除这条线会破坏我保护它们的目的 @that case you have to make proper or dynamic path Like "/employee/** kind of which accept up to Like employee/id/?any 【参考方案1】:这就是我消除 REST API 访问错误的方法。当我调用 API 时,它给了我 403 错误。 为了解决这个问题,我进行了这些更改。
-
我使用 mvcMatcher 代替 antMatcher 进行 API 映射
角色以“USER”或“ADMIN”之类的名称提供,而不是“ROLE_USER”或“ROLE_ADMIN”
代码如下:
@Configuration
@EnableWebSecurity
public class SecurityConfiguration extends WebSecurityConfigurerAdapter
@Override
protected void configure(HttpSecurity http) throws Exception
http
.csrf().disable().authorizeRequests()
.and()
.addFilter(new ApplicationAuthorizationFilter(authenticationManager()))
.authorizeRequests()
.antMatchers(ApplicationConstants.DEFAULT_API_CHECK_PATH).permitAll()
.mvcMatchers("/app/users/**/**").hasAnyRole("USER", "ADMIN")
.and()
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS);
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception
auth
.inMemoryAuthentication()
.withUser("abc").password("xyz").roles("READONLY") ;
@Bean
public PasswordEncoder encoder()
return new BCryptPasswordEncoder(ApplicationConstants.ENCODER_STRENGTH);
Spring Security 中提供了一个机制来决定是否应该在 GrantedAuthotrity 值之前添加前缀以及它应该是什么。默认为空白,因为我没有在我的情况下设置任何内容。
之前我试图将角色名称作为“ROLE_USER”传递,但失败了。
【讨论】:
【参考方案2】:在 Spring Security 中,roles 和 authorities 之间存在区别。虽然权限可以是任何东西,但角色是以ROLE_
开头的权限的子集。
假设您有以下权限:
GrantedAuthority authority1 = new SimpleGrantedAuthority("User");
GrantedAuthority authority2 = new SimpleGrantedAuthority("ROLE_Admin");
在这种情况下,authority1
不包含角色,而 authority2
包含角色,因为它以 ROLE_
为前缀。
这意味着,如果您使用hasRole("User")
,您将无权访问,因为它未定义为角色。另一方面,hasRole("Admin")
会起作用。
要解决这个问题,您有两种选择:
确保您的角色确实以ROLE_
为前缀。如果您不以这种方式将它们存储在您的数据库中,您可以修改您的UserDetailsServiceImpl
:
String roleName = "ROLE_" + role.getRole().toString();
grantedAuthorities.add(new SimpleGrantedAuthority(roleName));
或者,您可以改用hasAuthority("User")
:
// ...
.antMatchers("/employee", "/insurance").hasAuthority("User")
// ...
【讨论】:
感谢您的回答。我只是想让您知道,在安全配置类中更新 .antMatchers("/hr-core/employee/**", "/hr-core/insurance/**").hasRole("User") 后,现在可以访问 REST 端点。但我不确定安全类中的硬编码上下文路径是否正确。 @Karthik 你不应该那样做。您原来的 antmatcher 工作正常(除了如果所有子路径也应该工作,您可以在末尾添加/**
)。现在您已使该 antmatcher 无效,因为它现在将寻找 /hr-core/hr-core/employee/**
。由于不匹配,它将回退到anyRequest().authenticated()
。所以现在,您的基于角色的授权被绕过了(您可以通过尝试访问端点而不具有正确的User
角色来测试这一点)。
你是绝对正确的。基于角色的授权被绕过。我将根据您的回答更新我的代码并检查。再次感谢
你救了我的命!以上是关于Spring Boot 安全性中的 HTTP 403 禁止错误的主要内容,如果未能解决你的问题,请参考以下文章
Spring Boot 中的 Thymeleaf 缓存和安全性
使用 angularJS 的 Spring Boot 安全性/登录身份验证
在 Spring Boot 中使用 jwt 令牌的具有 http 安全性的 CrossOrigin
寻找 Spring Boot Hystrix Dashboard 解释(Spring Boot Starter)安全性的解决方案 Hystrix Stream(作为它自己的项目)?