Spring Boot RestController DELETE 请求在没有 .csrf().disable() 的情况下失败
Spring Boot RestController DELETE request fails without .csrf().disable()
我有一个 Spring 启动休息服务概念证明。
为了我的安全,我有这个:(显然是一个糟糕的实际实现)。
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
@Configuration
public class MySecurityConfiguration extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity httpSecurity) throws Exception {
/* not production grade quality */
httpSecurity.authorizeRequests().anyRequest().permitAll();
}
// @Override
// public void configure(WebSecurity web) throws Exception {
// web.debug(true);
// }
}
使用 Postman:
我所有的 GET 都工作正常。然后我添加了一个 DELETE 请求。得到
{
"timestamp": "blah blah blah",
"status": 403,
"error": "Forbidden",
"message": "Forbidden",
"path": "/v1/mything/1"
}
邮递员设置:(不是火箭科学)
DELETE
http://localhost:8080/v1/mythings/1
所以我添加了“.csrf().disable()”,我的 DELETE 起作用了。
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
@Configuration
public class MySecurityConfiguration extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity httpSecurity) throws Exception {
/* not production grade quality */
httpSecurity.csrf().disable(); /* had to add this "Cross Site Request Forgery" disable for DELETE operations */
httpSecurity.authorizeRequests().anyRequest().permitAll();
}
// @Override
// public void configure(WebSecurity web) throws Exception {
// web.debug(true);
// }
}
但我的问题是为什么 .csrf().disable() .. 允许删除请求?似乎 有点 无关。
谢谢。
下面是我的完全休息控制器:
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import javax.inject.Inject;
import java.time.OffsetDateTime;
import java.util.Collection;
import java.util.Optional;
import java.util.Set;
@RestController
@RequestMapping("/v1")
public class MyThingController {
private final Logger logger;
private final IMyThingManager mythingManager;
/* The Inject annotation is the signal for which constructor to use for IoC when there are multiple constructors. Not needed in single constructor scenarios */
@Inject
public MyThingController(IMyThingManager mythingManager) {
this(LoggerFactory.getLogger(MyThingController.class), mythingManager);
}
public MyThingController(Logger lgr, IMyThingManager mythingManager) {
if (null == lgr) {
throw new IllegalArgumentException("Logger is null");
}
if (null == mythingManager) {
throw new IllegalArgumentException("IMyThingManager is null");
}
this.logger = lgr;
this.mythingManager = mythingManager;
}
@RequestMapping(value = "/mythings", method = RequestMethod.GET)
Collection<MyThingDto> getAllMyThings() {
Collection<MyThingDto> returnItems = this.mythingManager.getAll();
return returnItems;
}
@RequestMapping(method = RequestMethod.GET, value = "mythings/{mythingKey}")
ResponseEntity<MyThingDto> getMyThingById(@PathVariable Long mythingKey) {
this.logger.info(String.format("Method getMyThingById called. (mythingKey=\"%1s\")", mythingKey));
Optional<MyThingDto> foundItem = this.mythingManager.getSingle(mythingKey);
ResponseEntity<MyThingDto> responseEntity = new ResponseEntity<>(HttpStatus.NOT_FOUND);
if (foundItem.isPresent()) {
responseEntity = new ResponseEntity<>(foundItem.get(), HttpStatus.OK);
}
return responseEntity;
}
@RequestMapping(value = "mythings/{mythingKey}", method = RequestMethod.DELETE, produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<Integer> deleteUser(@PathVariable("mythingKey") Long mythingKey) {
this.logger.info(String.format("Method deleteUser called. (mythingKey=\"%1s\")", mythingKey));
int rowCount = this.mythingManager.deleteByKey(mythingKey);
int rowCount = 1; /* use this to "fake it" */
ResponseEntity<Integer> responseEntity = new ResponseEntity<>(HttpStatus.NOT_FOUND);
if (rowCount > 0) {
responseEntity = new ResponseEntity<>(rowCount, HttpStatus.OK);
}
return responseEntity;
}
}
CSRF 保护会在更改 POST、PUT、DELETE 等方法时检查 CSRF 令牌。由于 REST API 是无状态的,因此您在 cookie 中没有令牌。这就是为什么您必须为 REST APIs.
禁用它
参考资料
我有一个 Spring 启动休息服务概念证明。
为了我的安全,我有这个:(显然是一个糟糕的实际实现)。
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
@Configuration
public class MySecurityConfiguration extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity httpSecurity) throws Exception {
/* not production grade quality */
httpSecurity.authorizeRequests().anyRequest().permitAll();
}
// @Override
// public void configure(WebSecurity web) throws Exception {
// web.debug(true);
// }
}
使用 Postman: 我所有的 GET 都工作正常。然后我添加了一个 DELETE 请求。得到
{
"timestamp": "blah blah blah",
"status": 403,
"error": "Forbidden",
"message": "Forbidden",
"path": "/v1/mything/1"
}
邮递员设置:(不是火箭科学)
DELETE
http://localhost:8080/v1/mythings/1
所以我添加了“.csrf().disable()”,我的 DELETE 起作用了。
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
@Configuration
public class MySecurityConfiguration extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity httpSecurity) throws Exception {
/* not production grade quality */
httpSecurity.csrf().disable(); /* had to add this "Cross Site Request Forgery" disable for DELETE operations */
httpSecurity.authorizeRequests().anyRequest().permitAll();
}
// @Override
// public void configure(WebSecurity web) throws Exception {
// web.debug(true);
// }
}
但我的问题是为什么 .csrf().disable() .. 允许删除请求?似乎 有点 无关。
谢谢。
下面是我的完全休息控制器:
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import javax.inject.Inject;
import java.time.OffsetDateTime;
import java.util.Collection;
import java.util.Optional;
import java.util.Set;
@RestController
@RequestMapping("/v1")
public class MyThingController {
private final Logger logger;
private final IMyThingManager mythingManager;
/* The Inject annotation is the signal for which constructor to use for IoC when there are multiple constructors. Not needed in single constructor scenarios */
@Inject
public MyThingController(IMyThingManager mythingManager) {
this(LoggerFactory.getLogger(MyThingController.class), mythingManager);
}
public MyThingController(Logger lgr, IMyThingManager mythingManager) {
if (null == lgr) {
throw new IllegalArgumentException("Logger is null");
}
if (null == mythingManager) {
throw new IllegalArgumentException("IMyThingManager is null");
}
this.logger = lgr;
this.mythingManager = mythingManager;
}
@RequestMapping(value = "/mythings", method = RequestMethod.GET)
Collection<MyThingDto> getAllMyThings() {
Collection<MyThingDto> returnItems = this.mythingManager.getAll();
return returnItems;
}
@RequestMapping(method = RequestMethod.GET, value = "mythings/{mythingKey}")
ResponseEntity<MyThingDto> getMyThingById(@PathVariable Long mythingKey) {
this.logger.info(String.format("Method getMyThingById called. (mythingKey=\"%1s\")", mythingKey));
Optional<MyThingDto> foundItem = this.mythingManager.getSingle(mythingKey);
ResponseEntity<MyThingDto> responseEntity = new ResponseEntity<>(HttpStatus.NOT_FOUND);
if (foundItem.isPresent()) {
responseEntity = new ResponseEntity<>(foundItem.get(), HttpStatus.OK);
}
return responseEntity;
}
@RequestMapping(value = "mythings/{mythingKey}", method = RequestMethod.DELETE, produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<Integer> deleteUser(@PathVariable("mythingKey") Long mythingKey) {
this.logger.info(String.format("Method deleteUser called. (mythingKey=\"%1s\")", mythingKey));
int rowCount = this.mythingManager.deleteByKey(mythingKey);
int rowCount = 1; /* use this to "fake it" */
ResponseEntity<Integer> responseEntity = new ResponseEntity<>(HttpStatus.NOT_FOUND);
if (rowCount > 0) {
responseEntity = new ResponseEntity<>(rowCount, HttpStatus.OK);
}
return responseEntity;
}
}
CSRF 保护会在更改 POST、PUT、DELETE 等方法时检查 CSRF 令牌。由于 REST API 是无状态的,因此您在 cookie 中没有令牌。这就是为什么您必须为 REST APIs.
禁用它参考资料