简体   繁体   English

如何使用 fetch api 在 post 请求中正确验证?

[英]How to authenticate properly in post request with fetch api?

  • I have a SpringBoot Backend with Spring Security Enabled in the default configuration (nothing changed there).我有一个 SpringBoot 后端,在默认配置中启用了 Spring Security(那里没有任何变化)。

  • I have following Rest Controller and Post Mapping:我有以下 Rest Controller 和 Post Mapping:


@RestController
public class MyController {

    @PostMapping(value = "/sm/resrc/pth")
    public Integer postSomething(@RequestParam String someValue,@RequestParam String userId){
        System.out.println(String.format("SomeValue: %s from userid %s",someValue,userId));
        return 0;
    }

}
  • Creating a Post request from the following form works fine:从以下表单创建 Post 请求工作正常:
<form method="post" th:action="@{/sm/resrc/pth}">
     <input type="text" name="someValue">
     <input type="text" name="userId">
     <input type="hidden" name="_csrf" value="${_csrf.token}" />
     <div><input type="submit" value="Send" /></div>
</form>

It does even work without the hidden cors value.它甚至可以在没有隐藏 cors 值的情况下工作。

  • However I need to create a post request from JavaScript, which doesn't work.但是我需要从 JavaScript 创建一个 post 请求,这不起作用。 The SpringBoot application is running at localhost:8080 . SpringBoot 应用程序在localhost:8080 上运行。 I thought, the credentials parameter 'include' is used for including the required authentication headers, which the user already entered successfully to open the given page.我认为,凭证参数“include”用于包含所需的身份验证标头,用户已成功输入该标头以打开给定页面。 Is this correct?这样对吗? I also changed the value of 'mode' .我还更改了'mode'的值。 I tried 'cors' , 'same-origin' and 'no-cors' .我试过'cors''same-origin''no-cors' It just does't work.它只是不起作用。 I event don't understand why cors is a problem anyway as I am requesting a resource from the same origin.我事件不明白为什么 cors 是一个问题,因为我正在请求来自同一来源的资源。 It didn't even work after adding the Authorization header manually to the request without using the credentials parameter.As you can see in the image I always get the 403 status.在不使用凭据参数的情况下将授权标头手动添加到请求后,它甚至不起作用。正如您在图像中看到的,我总是得到 403 状态。 What is wrong with my request?我的请求有什么问题? What am I missing?我错过了什么?
let data = {
            "some":"abc",
            "values":this.localDescription,
            "userId":userId
        };

fetch("sm/resrc/pth",
            {
                method: 'POST',
                credentials: 'include',
                mode: 'cors',
                body: data
            }
        ).then(response => console.log(response));

回复截图

I've found the same problem doing a login example with jax-rs.我在用 jax-rs 做一个登录示例时发现了同样的问题。 In my case the problem was that when add the 'credentials': 'include' to the request, on the side of the Rest Service API, need configure in the CORS Filter the header from:在我的情况下,问题是当向请求添加 'credentials': 'include' 时,在 Rest Service API 一侧,需要在 CORS 过滤器中配置标头:

response.addHeader("Access-Control-Allow-Origin", "*");

to:到:

res.addHeader("Access-Control-Allow-Origin", "http://localhost");

Where "http://localhost is the origin of my request.其中“http://localhost 是我请求的来源。

I've found information about it in this post: No 'Access-Control-Allow-Origin' header is present on the requested resource—when trying to get data from a REST API我在这篇文章中找到了有关它的信息: 请求的资源上不存在“Access-Control-Allow-Origin”标头—当尝试从 REST API 获取数据时

CORS is a security feature; CORS 是一项安全功能; So you probably don't want to disable or bypass it.所以你可能不想禁用或绕过它。 I struggled a bit to find out, how to include the headers correctly but finally found the solution.我努力找出如何正确包含标题,但最终找到了解决方案。 That's how I solved it:我就是这样解决的:

In the first step I added the expected CSRF-Header-name and the token itself to the metadata of the generated html file.在第一步中,我将预期的 CSRF-Header-name 和令牌本身添加到生成的 html 文件的元数据中。 In spring using the templating framework thyemleaf it looks like following:在春季使用模板框架 thyemleaf 时,它看起来如下所示:

<html lang="en">
    <head>
        <meta name="_csrf_header_name" th:content="${_csrf.headerName}"/> 
        <meta name="_csrf_token" th:content="${_csrf.token}"/>
               
    </head>
    .
    .
    .
</html>

Which results in something like that:结果是这样的:


<meta name="_csrf_header_name" content="X-CSRF-TOKEN">
<meta name="_csrf_token" content="14d98c88-8643-1234-5678-39473aa7890e">

In the fetch request, the CSRF Header is built from the token and the correct Header-name (which are read from the meta tags) just as expected from the server.在获取请求中,CSRF Header 是从令牌和正确的 Header-name(从元标记中读取)构建的,正如服务器所预期的那样。

getCsrfToken(){
   return document.querySelector('meta[name=_csrf_token]').content;
}

getCsrfTokenName(){
   return document.querySelector('meta[name=_csrf_header_name]').content;
}
 
let csrfToken = this.getCsrfToken();
let csrfTokenName = this.getCsrfTokenName();
        
fetch('sm/resrc/pth', {
          method:'post',
          headers: new Headers([[csrfTokenName, csrfToken]])
        }).then(res =>{console.log(res);});}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM