繁体   English   中英

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

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

  • 我有一个 SpringBoot 后端,在默认配置中启用了 Spring Security(那里没有任何变化)。

  • 我有以下 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;
    }

}
  • 从以下表单创建 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>

它甚至可以在没有隐藏 cors 值的情况下工作。

  • 但是我需要从 JavaScript 创建一个 post 请求,这不起作用。 SpringBoot 应用程序在localhost:8080 上运行。 我认为,凭证参数“include”用于包含所需的身份验证标头,用户已成功输入该标头以打开给定页面。 这样对吗? 我还更改了'mode'的值。 我试过'cors''same-origin''no-cors' 它只是不起作用。 我事件不明白为什么 cors 是一个问题,因为我正在请求来自同一来源的资源。 在不使用凭据参数的情况下将授权标头手动添加到请求后,它甚至不起作用。正如您在图像中看到的,我总是得到 403 状态。 我的请求有什么问题? 我错过了什么?
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));

回复截图

我在用 jax-rs 做一个登录示例时发现了同样的问题。 在我的情况下,问题是当向请求添加 'credentials': 'include' 时,在 Rest Service API 一侧,需要在 CORS 过滤器中配置标头:

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

到:

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

其中“http://localhost 是我请求的来源。

我在这篇文章中找到了有关它的信息: 请求的资源上不存在“Access-Control-Allow-Origin”标头—当尝试从 REST API 获取数据时

CORS 是一项安全功能; 所以你可能不想禁用或绕过它。 我努力找出如何正确包含标题,但最终找到了解决方案。 我就是这样解决的:

在第一步中,我将预期的 CSRF-Header-name 和令牌本身添加到生成的 html 文件的元数据中。 在春季使用模板框架 thyemleaf 时,它看起来如下所示:

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

结果是这样的:


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

在获取请求中,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