如何在使用 fetch api 的 post 请求中正确验证?
How to authenticate properly in post request with fetch api?
我有一个 Spring 启动后端,在默认配置中启用了 Spring 安全性(那里没有任何改变)。
我有以下 Rest 控制器和 Post 映射:
@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 请求,但这是行不通的。 Spring启动应用程序 运行 位于 localhost:8080。我认为,credentials 参数 'include' 用于包含用户已经输入的所需身份验证 headers成功打开指定页面。这样对吗?我还更改了 'mode' 的值。我尝试了 'cors'、'same-origin' 和 'no-cors'。它只是行不通。我不明白为什么 cors 无论如何都是一个问题,因为我正在请求来自同一来源的资源。在不使用凭据 parameter.As 手动向请求添加授权 header 之后,它甚至没有工作,您可以在图像中看到我总是获得 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 服务 API 的一侧,需要在 CORS 中配置 Filter the header from:
response.addHeader("Access-Control-Allow-Origin", "*");
至:
res.addHeader("Access-Control-Allow-Origin", "http://localhost");
其中“http://localhost 是我请求的来源。
我在这个 post 中找到了有关它的信息:
CORS 是一项安全功能;所以你可能不想禁用或绕过它。我努力寻找如何正确包含 header 的方法,但最终找到了解决方案。我就是这样解决的:
在第一步中,我将预期的 CSRF-Header-name 和令牌本身添加到生成的 html 文件的元数据中。在 spring 使用模板框架 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">
创建提取请求时,header 名称的值和令牌本身会从元标记中读取。这样 csrf header 看起来就像服务器期望的那样。这是主要原因,也是我为这个请求苦苦挣扎的原因。我不知道,我将令牌的 Header 名称命名为错误。预期的 Header/Token 名称可能因服务器而异 - 我猜;因此可能会有所不同,具体取决于您的后端。
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);});}
我有一个 Spring 启动后端,在默认配置中启用了 Spring 安全性(那里没有任何改变)。
我有以下 Rest 控制器和 Post 映射:
@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 请求,但这是行不通的。 Spring启动应用程序 运行 位于 localhost:8080。我认为,credentials 参数 'include' 用于包含用户已经输入的所需身份验证 headers成功打开指定页面。这样对吗?我还更改了 'mode' 的值。我尝试了 'cors'、'same-origin' 和 'no-cors'。它只是行不通。我不明白为什么 cors 无论如何都是一个问题,因为我正在请求来自同一来源的资源。在不使用凭据 parameter.As 手动向请求添加授权 header 之后,它甚至没有工作,您可以在图像中看到我总是获得 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 服务 API 的一侧,需要在 CORS 中配置 Filter the header from:
response.addHeader("Access-Control-Allow-Origin", "*");
至:
res.addHeader("Access-Control-Allow-Origin", "http://localhost");
其中“http://localhost 是我请求的来源。
我在这个 post 中找到了有关它的信息:
CORS 是一项安全功能;所以你可能不想禁用或绕过它。我努力寻找如何正确包含 header 的方法,但最终找到了解决方案。我就是这样解决的:
在第一步中,我将预期的 CSRF-Header-name 和令牌本身添加到生成的 html 文件的元数据中。在 spring 使用模板框架 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">
创建提取请求时,header 名称的值和令牌本身会从元标记中读取。这样 csrf header 看起来就像服务器期望的那样。这是主要原因,也是我为这个请求苦苦挣扎的原因。我不知道,我将令牌的 Header 名称命名为错误。预期的 Header/Token 名称可能因服务器而异 - 我猜;因此可能会有所不同,具体取决于您的后端。
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);});}