重命名:带有Angular和Spring的CSRF(“不支持请求方法'DELETE'”)

时间:2018-12-27 23:09:49

标签: spring spring-boot angular7

我正在尝试调用控制器的delete方法:

春天:

@RestController
@RequestMapping("/api")
@CrossOrigin
public class Controller
{
    @DeleteMapping("thing/item/{name}")
    public void deleteThing(@PathVariable String name)
    {
        System.out.println("CALL"); // Never called!!!
    }
}

角度7:

deleteTemplate(name: string) {
    const url = `host/api/thing/item/${name}`;
    return this.http.delete(url);
}

我发现了一些有关包括选项的信息:​​

httpOptions = {
    headers: new HttpHeaders({ 'Content-Type': 'application/json' })
};

deleteTemplate(name: string) {
    const url = `${host}/api/thing/item/${name}`; // host is not relevant, same path with GET works.
    return this.http.delete(url, this.httpOptions);
}

但是我什至不需要,因为我发送的所有内容都在链接本身中(没有json)。

每次:

WARN 15280 --- [io-8443-exec-10] .w.s.m.s.DefaultHandlerExceptionResolver : Resolved [org.springframework.web.HttpRequestMethodNotSupportedException: Request method 'DELETE' not supported]

该如何解决?

DELETE发送时出现405错误,并且前面有OPTIONS(带有200码)。它到达服务器并出现此错误。

编辑

以上是经过简化但仍然无法正常工作的代码示例。我理解您的意见,但主持人可以是任何东西,在这里无关紧要。如前所述,它的本地主机-在达到端点的意义上起作用。

要检查我是否做错了,我这样做了:

@Autowired
private RequestMappingHandlerMapping requestMappingHandlerMapping;

this.requestMappingHandlerMapping.getHandlerMethods()
                .forEach((e, k) -> System.out.println(e + "   OF   " + k));

启动后,它会打印出我期望的所有内容,包括:

{GET /api/thing/item/{name}}   OF   public myPackage.Thing myPackage.Controller.getThing(java.lang.String)
{DELETE /api/thing/item/{name}}   OF   public void myPackage.Controller.deleteThing(java.lang.String)

有什么想法吗?

2 个答案:

答案 0 :(得分:0)

在路径的开头添加斜杠/。

@DeleteMapping("/thing/item/{name}")

答案 1 :(得分:0)

该死。原来问题出在CSRF,主要是在隐藏的Angular文档和误导性的Spring过滤器日志中。

我花了大约10个小时才使它工作,但仅在生产中使用(Angular与Spring在同一主机/端口上)。我将尝试使其在dev中工作,但是基本上需要重写Angular提供的绑定到其默认值的整个模块。

现在要解决这个问题:

当我们想使用CSRF时,一切都始于Spring Security。如果CsrfFilter与预期的CSRF令牌不匹配,显然会爆炸,然后退回到/error。这一切都是在没有任何特定日志消息的情况下发生的,而是简单的Request method 'DELETE' not supported,根据我的问题,我们知道它存在。

这不仅适用于DELETE,而且适用于所有操作请求(non-GET/HEAD)。

所有这些都指向“如何使用Angular设置CSRF?”。好吧,我们开始:

并且默认运行。基于CSRF的Cookie-Header机制。

但是等等,还有更多!

Spring需要为Cookie-Header机制配置bo。我们很高兴得到:

@Override
protected void configure(HttpSecurity http) throws Exception
{
    http.csrf().csrfTokenRepository(this.csrfRepo());
}

private CookieCsrfTokenRepository csrfRepo()
{
    CookieCsrfTokenRepository repo = new CookieCsrfTokenRepository();
    repo.setCookieHttpOnly(false);
    return repo;
}

这是Spring内置的,实际上使用与Angular相同的cookie /标题名称。但是repo.setCookieHttpOnly(false);怎么了?好吧...另一个可怜的记录物。您只需要将其设置为false,否则Angular的一侧将无法工作。

再次-这仅适用于生产版本,因为Angular不支持外部链接。更多信息,请访问:Angular 6 does not add X-XSRF-TOKEN header to http request

是的...要使其在具有2个服务器的dev localhost中工作,我将需要第1个来重新创建https://angular.io/api/common/http/HttpClientXsrfModule机制来拦截非默认请求。

编辑

基于JB Nizet的评论,我整理了适用于开发人员和生产人员的安装程序。确实,代理很棒。启用CSRF和SSL(以我为例),您还需要在Angular CLI上启用SSL,否则Angular将无法使用启用SSL的代理后端的CSRF,因此不起作用。

"serve": {
    "options": {
            "proxyConfig": "proxy.conf.json",
            "sslKey": "localhost.key",
            "sslCert": "localhost.crt",
            "ssl": true
    }
}

请注意,如果找不到证书和密钥,则会自动生成:) 对于Spring后端,您不需要相同的证书。我在那里使用单独的JKS。

干杯!

enter image description here