在 Web Inspector 中找不到 HttpOnly Cookie
HttpOnly Cookies not found in Web Inspector
我正在为使用 MERN 堆栈构建的网站进行用户身份验证,我决定使用存储为 HttpOnly cookie 的 JWT 令牌。当我使用 Postman 发出请求但不是在 Safari Web Inspector 中时,cookie 是在响应 header 的“Set-Cookie”字段中发送的,如下图所示。在存储选项卡中也没有找到 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, res, 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 错误。此外,没有抛出任何错误,我网页上所有其他 API 不涉及 cookie 的请求也能正常工作。
另一个有趣的事情是,尽管对 Postman 和 React 代码使用相同的数据(包含 {username:"Joshua", password:"qwerty"} 的 JS object),validCredentials 的计算结果为 true在 Postman 中,在 Web Inspector 中为 false。它是我数据库中的一个现有文档,我希望返回的值是 true,在我添加 cookies
之前就是这种情况
请问我做错了什么,或者您对我如何解决这个问题有什么建议吗?我是 web-development
的初学者
编辑
根据 dave 的回答,我可以在前端收到“Set-Cookie”header。但是由于某种原因,它没有出现在网络检查器的“存储”选项卡中。
这是回复header
这是通常显示网站 cookie 的“存储”选项卡
如果您尝试将请求发送为 json,则需要设置内容类型 header,并且 JSON.stringify
object:
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 设置在另一个块中。
我正在为使用 MERN 堆栈构建的网站进行用户身份验证,我决定使用存储为 HttpOnly cookie 的 JWT 令牌。当我使用 Postman 发出请求但不是在 Safari Web Inspector 中时,cookie 是在响应 header 的“Set-Cookie”字段中发送的,如下图所示。在存储选项卡中也没有找到 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, res, 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 错误。此外,没有抛出任何错误,我网页上所有其他 API 不涉及 cookie 的请求也能正常工作。
另一个有趣的事情是,尽管对 Postman 和 React 代码使用相同的数据(包含 {username:"Joshua", password:"qwerty"} 的 JS object),validCredentials 的计算结果为 true在 Postman 中,在 Web Inspector 中为 false。它是我数据库中的一个现有文档,我希望返回的值是 true,在我添加 cookies
之前就是这种情况请问我做错了什么,或者您对我如何解决这个问题有什么建议吗?我是 web-development
的初学者编辑
根据 dave 的回答,我可以在前端收到“Set-Cookie”header。但是由于某种原因,它没有出现在网络检查器的“存储”选项卡中。
这是回复header
这是通常显示网站 cookie 的“存储”选项卡
如果您尝试将请求发送为 json,则需要设置内容类型 header,并且 JSON.stringify
object:
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 设置在另一个块中。