spring 启动安全性中的 HTTP 403 禁止错误
HTTP 403 forbidden error in spring boot security
Spring 安全配置 class
@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 实现 class
@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);
}
}
员工休息控制器class
@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[=15= 的任何 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 请求的基本身份验证 header(授权)中发送了正确的用户名和密码,我仍然收到此错误。该用户还同时具有 USER 和 ADMIN 角色来访问 /employee REST 端点。我在 http 安全中禁用了 CSRF。
如何解决这个错误?
在 Spring 安全性中,角色 和 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")
// ...
这就是我消除 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 安全性中有一种机制可以确定是否应在 GrantedAuthotrity 值之前添加前缀以及它应该是什么。默认为空白,因为我没有在我的案例中设置任何内容。
之前我试图将角色名称作为“ROLE_USER”传递,但失败了。
Spring 安全配置 class
@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 实现 class
@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);
}
}
员工休息控制器class
@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[=15= 的任何 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 请求的基本身份验证 header(授权)中发送了正确的用户名和密码,我仍然收到此错误。该用户还同时具有 USER 和 ADMIN 角色来访问 /employee REST 端点。我在 http 安全中禁用了 CSRF。
如何解决这个错误?
在 Spring 安全性中,角色 和 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") // ...
这就是我消除 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 安全性中有一种机制可以确定是否应在 GrantedAuthotrity 值之前添加前缀以及它应该是什么。默认为空白,因为我没有在我的案例中设置任何内容。
之前我试图将角色名称作为“ROLE_USER”传递,但失败了。