Spring boot Spring Boot RestController删除请求在没有.csrf()的情况下失败。禁用()

Spring boot Spring Boot RestController删除请求在没有.csrf()的情况下失败。禁用(),spring-boot,spring-restcontroller,Spring Boot,Spring Restcontroller,我有一个弹簧靴休息服务的概念证明 我有这个是为了我的安全:(显然是一个糟糕的实际实现) 使用邮递员: 我所有的工作都很好。然后我添加了一个删除请求。得到 { "timestamp": "blah blah blah", "status": 403, "error": "Forbidden", "message": "Forbidden", "path": "/v1/mything/1" } 邮递员设置:(非火箭科学) 因此,我添加了“.csrf().di

我有一个弹簧靴休息服务的概念证明

我有这个是为了我的安全:(显然是一个糟糕的实际实现)

使用邮递员: 我所有的工作都很好。然后我添加了一个删除请求。得到

{
    "timestamp": "blah blah blah",
    "status": 403,
    "error": "Forbidden",
    "message": "Forbidden",
    "path": "/v1/mything/1"
}
邮递员设置:(非火箭科学)

因此,我添加了“.csrf().disable()”,我的删除就可以了

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;
    }


}
import org.slf4j.Logger;
导入org.slf4j.LoggerFactory;
导入org.springframework.format.annotation.DateTimeFormat;
导入org.springframework.http.HttpStatus;
导入org.springframework.http.MediaType;
导入org.springframework.http.ResponseEntity;
导入org.springframework.web.bind.annotation.PathVariable;
导入org.springframework.web.bind.annotation.RequestMapping;
导入org.springframework.web.bind.annotation.RequestMethod;
导入org.springframework.web.bind.annotation.RestController;
导入javax.inject.inject;
导入java.time.OffsetDateTime;
导入java.util.Collection;
导入java.util.Optional;
导入java.util.Set;
@RestController
@请求映射(“/v1”)
公共类MyThingController{
私人最终记录器;
私人最终投资经理mythingManager;
/*当存在多个构造函数时,Inject注释是IoC使用哪个构造函数的信号。在单个构造函数场景中不需要*/
@注入
公共MyThingController(IMyThingManager mythingManager){
这是(LoggerFactory.getLogger(MyThingController.class)、mythingManager);
}
公共MyThingController(记录器lgr、IMyThingManager mythingManager){
if(null==lgr){
抛出新的IllegalArgumentException(“记录器为空”);
}
if(null==mythingManager){
抛出新的IllegalArgumentException(“IMyThingManager为空”);
}
this.logger=lgr;
this.mythingManager=mythingManager;
}
@RequestMapping(value=“/mythings”,method=RequestMethod.GET)
集合getAllMyThings(){
Collection returnItems=this.mythingManager.getAll();
归还物品;
}
@RequestMapping(method=RequestMethod.GET,value=“mythings/{mythingKey}”)
ResponseEntity getMyThingById(@PathVariable Long mythingKey){
this.logger.info(String.format(“调用了getMyThingById方法。(mythingKey=\%1s\”),mythingKey));
可选foundItem=this.mythingManager.getSingle(mythingKey);
ResponseEntity ResponseEntity=新的ResponseEntity(HttpStatus.NOT_FOUND);
if(foundItem.isPresent()){
responseEntity=新的responseEntity(foundItem.get(),HttpStatus.OK);
}
返回响应性;
}
@RequestMapping(value=“mythings/{mythingKey}”,method=RequestMethod.DELETE,products=MediaType.APPLICATION\u JSON\u value)
public ResponseEntity deleteUser(@PathVariable(“mythingKey”)长mythingKey){
this.logger.info(String.format(“方法deleteUser调用。(mythingKey=\%1s\”),mythingKey));
int rowCount=this.mythingManager.deleteByKey(mythingKey);
int rowCount=1;/*使用此选项“伪造”*/
ResponseEntity ResponseEntity=新的ResponseEntity(HttpStatus.NOT_FOUND);
如果(行计数>0){
responseEntity=新的responseEntity(行数,HttpStatus.OK);
}
返回响应性;
}
}

CSRF保护在更改POST、PUT、DELETE等方法时检查CSRF令牌。由于RESTAPI是无状态的,所以cookie中没有令牌。这就是为什么您必须为RESTAPI禁用它

参考资料

  • Spring安全参考:

  • 弹簧中CSRF保护指南

CSRF保护在更改POST、PUT、DELETE等方法时检查CSRF令牌。由于RESTAPI是无状态的,所以cookie中没有令牌。这就是为什么你必须为REST API禁用它这能回答你的问题吗?如果是,我会添加我的评论作为答案,并添加一些链接。别忘了我的措辞精辟而清晰的问题。:)当然可以;-)。。。。。。。
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);
//    }

}
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;
    }


}