问题描述
我正在为使用MERN堆栈构建的网站进行用户身份验证,我决定使用存储为HttpOnly cookie的JWT令牌。当我使用Postman发出请求时,该cookie在响应标头中的“ Set-Cookie”字段中发送,而不是在Safari Web Inspector中发送,如下图所示。在存储标签中也没有找到Cookie。
我已将我的React登录表单简化为一个按钮,该按钮用于调试以提交用户名和密码
import React from "react";
const sendRequest = async (event) => {
event.preventDefault();
let response;
try {
response = await fetch("http://localhost:5000/api/user/login",{
method: "POST",body: { username: "Joshua",password: "qwerty" },mode: "cors",// include cookies/ authorization headers
credentials: "include",});
} catch (err) {
console.log(err);
}
if (response) {
const responseData = await response.json();
console.log(responseData);
}
};
const test = () => {
return (
<div>
<input type="button" onClick={sendRequest} value="send" />
</div>
);
};
export default test;
我在后端使用了express,这是我的index.js,其中所有传入请求都首先收到
const app = express();
app.use(bodyParser.json());
app.use("/images",express.static("images"));
app.use((req,res,next) => {
res.set({
"Access-Control-Allow-Origin": req.headers.origin,"Access-Control-Allow-Credentials": "true","Access-Control-Allow-Headers": "Content-Type,*","Access-Control-Allow-Methods": "GET,POST,PATCH,DELETE",});
next();
});
app.use(cookieParser());
// api requests for user info/ login/signup
app.use("/api/user",userRoutes);
这是最终将登录请求定向到的中间件
const login = async (req,next) => {
const { username,password } = req.body;
let existingUser;
let validCredentials;
let userID;
let accesstoken;
try {
existingUser = await User.findOne({ username });
} catch (err) {
return next(new DatabaseError(err.message));
}
// if user cannot be found -> username is wrong
if (!existingUser) {
validCredentials = false;
} else {
let isValidPassword = false;
try {
isValidPassword = await bcrypt.compare(password,existingUser.password);
} catch (err) {
return next(new DatabaseError(err.message));
}
// if password is wrong
if (!isValidPassword) {
validCredentials = false;
} else {
try {
await existingUser.save();
} catch (err) {
return next(new DatabaseError(err.message));
}
userID = existingUser.id;
validCredentials = true;
accesstoken = jwt.sign({ userID },SECRET_JWT_HASH);
res.cookie("access_token",accesstoken,{
maxAge: 3600,httpOnly: true,});
}
}
res.json({ validCredentials });
};
其他信息
在登录中间件中,设置了一个validCredentials布尔值并将其返回给客户端。我能够在前端检索此值,因此我认为这不是CORS错误。此外,没有引发任何错误,并且我网页上的所有其他不涉及Cookie的API请求也可以正常工作。
另一个有趣的事情是,尽管对Postman和React代码使用了相同的数据(包含{username:“ Joshua”,密码:“ qwerty”}的JS对象),validCredentials在Postman中的计算结果为true,而在postman中的计算结果为false。 Web检查器。这是我数据库中的一个现有文档,我希望返回的值是true,在添加cookie之前就是这种情况
我是否可以知道我做错了什么,或者您对我如何解决此问题有任何建议?我是网络开发的初学者
编辑
有了戴夫的回答,我可以在前端收到“ Set-Cookie”标头。但是由于某种原因,它没有出现在Web检查器的“存储”选项卡中。
这是响应头
解决方法
如果您尝试将请求作为json发送,则需要设置内容类型标头和JSON.stringify
对象:
response = await fetch("http://localhost:5000/api/user/login",{
method: "POST",headers: { 'Content-Type': 'application/json' },body: JSON.stringify({ username: "Joshua",password: "qwerty" }),mode: "cors",// include cookies/ authorization headers
credentials: "include",});
现在您可能会得到与
相同的结果existingUser = User.findOne({ username: undefined})
所以当您这样做:
if (!existingUser) {
validCredentials = false;
} else { /* ... */ }
您将获得validCredentials = false
块,并且cookie在另一个块中设置。