HttpOnly cookie 不随请求一起发送到服务器
HttpOnly cookies are not sent with request to server
我在 node express 中创建了 API,我在端口 :8000
上 运行,我正在通过端口 API 上的简单 CRA 使用 APIs =20=]。我已经通过设置 httpOnly cookie 创建了注册和登录。此外,我已经放置了中间件来检查每个端点以验证它是否具有该令牌。
当我通过 Thunder/Postman 进行测试时,一切正常,登录后我得到 cookie 作为响应,我将该 cookie 设置为身份验证令牌并发出请求以获取数据,然后我得到了数据。
当我通过 React Frontend 登录时,它成功了,我可以在网络选项卡中看到我已经收到响应的 cookie。但是当我向受保护端点发出请求时,请求中没有 cookie(我在服务器上记录传入请求并比较使用 Thunder/Postman 客户端和通过浏览器中的应用程序发出的请求)。
我用的是 axios,我已经把它 {withCredentials: true}
它不起作用了。我使用了 withAxios
钩子,但它也不起作用。
服务器
index.js
...
const app = express()
app.use(cors({
credentials: true,
origin: 'http://localhost:3000',
}));
...
controllers/User.js
...
const loginUser = async(req, res) => {
const body = req.body
const user = await User.findOne({ email: body.email })
if(user) {
const token = generateToken(user)
const userObject = {
userId: user._id,
userEmail: user.email,
userRole: user.role
}
const validPassword = await bcrypt.compare(body.password, user.password)
if(validPassword) {
res.set('Access-Control-Allow-Origin', req.headers.origin);
res.set('Access-Control-Allow-Credentials', 'true');
res.set(
'Access-Control-Expose-Headers',
'date, etag, access-control-allow-origin, access-control-allow-credentials'
)
res.cookie('auth-token', token, {
httpOnly: true,
sameSite: 'strict'
})
res.status(200).json(userObject)
} else {
res.status(400).json({ error: "Invalid password" })
}
} else {
res.status(401).json({ error: "User doesn't exist" })
}
}
...
middleware.js
...
exports.verify = (req, res, next) => {
const token = req.headers.authorization
if(!token) res.status(403).json({ error: "please provide a token" })
else {
jwt.verify(token.split(" ")[1], tokenSecret, (err, value) => {
if(err) res.status(500).json({error: "failed to authenticate token"})
req.user = value.data
next()
})
}
}
...
router.js
...
router.get('/bills', middleware.verify, getBills)
router.post('/login', loginUser)
...
客户
src/components/LoginComponent.js
...
const loginUser = (e) => {
setLoading(true)
e.preventDefault()
let payload = {email: email, password: password}
axios.post('http://localhost:8000/login', payload).then(res => res.status === 200
? (setLoading(false), navigate('/listbills')) : navigate('/register'))
}
...
src/components/ListBills.js
...
useEffect(() => {
fetch('http://localhost:8000/bills', {
method: 'get',
headers: {'Content-Type': 'application/json'},
credentials: 'include',
})
.then(response => {console.log(response)}).catch(err => console.log(err));
}, [])
...
我也试过:
axios.get('http://localhost:8000/bills',{withCredentials: true})
.then((data) => console.log(data))
.then((result) => console.log(result))
.catch((err) => console.log('[Control Error ] ', err))
}
和
const [{ data, loading, error }, refetch] = useAxios(
'http://localhost:8000/bills',{
withCredentials: true,
headers: {'Access-Control-Allow-Origin': '*', 'Content-Type': 'application/json'
}})
Console.log 错误:
登录后,我在“网络”选项卡中看到了这个:
但是当我想访问列表时:
===更新===
所以问题的原因是没有在请求中传递 httpOnly cookie header。这是我正在使用的中间件的日志:
token undefined
req headers auth undefined
req headers {
host: 'localhost:8000',
connection: 'keep-alive',
'sec-ch-ua': '" Not;A Brand";v="99", "Google Chrome";v="97", "Chromium";v="97"',
'sec-ch-ua-mobile': '?0',
'user-agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/97.0.4692.99 Safari/537.36',
'sec-ch-ua-platform': '"macOS"',
'content-type': 'application/json',
accept: '*/*',
origin: 'http://localhost:3000',
'sec-fetch-site': 'same-site',
'sec-fetch-mode': 'cors',
'sec-fetch-dest': 'empty',
referer: 'http://localhost:3000/',
'accept-encoding': 'gzip, deflate, br',
'accept-language': 'en-US,en;q=0.9,hr;q=0.8,sr;q=0.7,bs;q=0.6,de;q=0.5,fr;q=0.4,it;q=0.3'
}
令牌是从 headers.authorization
中读取的,但是从 headers
的日志中它不存在,所以我的请求无法获得授权。
还是不行。
在阅读了 CORS
和 httpOnly cookies
上的所有内容后,我设法让它工作了。
首先,我删除了 sameSite
并根据 controllers/User.js
on SERVER
中的文档添加了 domain
道具
res.cookie('auth-token', token, {
httpOnly: true,
domain: 'http://localhost:3000'
})
然后我在控制台请求视图中看到一个黄色的小三角形,它表示域无效。然后我只是将 domain
更改为 origin
并且cookie出现在 headers
的请求日志中
res.cookie('auth-token', token, {
httpOnly: true,
origin: 'http://localhost:3000',
})
cookie 不在 headers
的 Authorization
属性 中,而是在 cookie
中,所以我不得不更改 middleware.js
中的代码因为它期望格式 bearer xxyyzz
但收到 auth-token=xxyyzz
,所以现在看起来像这样:
exports.verify = (req, res, next) => {
const token = req.headers.cookie
if(!token) res.status(403).json({ error: "please provide a token" })
else {
jwt.verify(token.split("=")[1], tokenSecret, (err, value) => {
if(err) res.status(500).json({error: "failed to authenticate token"})
req.user = value.data
next()
})
}
}
我在 node express 中创建了 API,我在端口 :8000
上 运行,我正在通过端口 API 上的简单 CRA 使用 APIs =20=]。我已经通过设置 httpOnly cookie 创建了注册和登录。此外,我已经放置了中间件来检查每个端点以验证它是否具有该令牌。
当我通过 Thunder/Postman 进行测试时,一切正常,登录后我得到 cookie 作为响应,我将该 cookie 设置为身份验证令牌并发出请求以获取数据,然后我得到了数据。
当我通过 React Frontend 登录时,它成功了,我可以在网络选项卡中看到我已经收到响应的 cookie。但是当我向受保护端点发出请求时,请求中没有 cookie(我在服务器上记录传入请求并比较使用 Thunder/Postman 客户端和通过浏览器中的应用程序发出的请求)。
我用的是 axios,我已经把它 {withCredentials: true}
它不起作用了。我使用了 withAxios
钩子,但它也不起作用。
服务器
index.js
...
const app = express()
app.use(cors({
credentials: true,
origin: 'http://localhost:3000',
}));
...
controllers/User.js
...
const loginUser = async(req, res) => {
const body = req.body
const user = await User.findOne({ email: body.email })
if(user) {
const token = generateToken(user)
const userObject = {
userId: user._id,
userEmail: user.email,
userRole: user.role
}
const validPassword = await bcrypt.compare(body.password, user.password)
if(validPassword) {
res.set('Access-Control-Allow-Origin', req.headers.origin);
res.set('Access-Control-Allow-Credentials', 'true');
res.set(
'Access-Control-Expose-Headers',
'date, etag, access-control-allow-origin, access-control-allow-credentials'
)
res.cookie('auth-token', token, {
httpOnly: true,
sameSite: 'strict'
})
res.status(200).json(userObject)
} else {
res.status(400).json({ error: "Invalid password" })
}
} else {
res.status(401).json({ error: "User doesn't exist" })
}
}
...
middleware.js
...
exports.verify = (req, res, next) => {
const token = req.headers.authorization
if(!token) res.status(403).json({ error: "please provide a token" })
else {
jwt.verify(token.split(" ")[1], tokenSecret, (err, value) => {
if(err) res.status(500).json({error: "failed to authenticate token"})
req.user = value.data
next()
})
}
}
...
router.js
...
router.get('/bills', middleware.verify, getBills)
router.post('/login', loginUser)
...
客户
src/components/LoginComponent.js
...
const loginUser = (e) => {
setLoading(true)
e.preventDefault()
let payload = {email: email, password: password}
axios.post('http://localhost:8000/login', payload).then(res => res.status === 200
? (setLoading(false), navigate('/listbills')) : navigate('/register'))
}
...
src/components/ListBills.js
...
useEffect(() => {
fetch('http://localhost:8000/bills', {
method: 'get',
headers: {'Content-Type': 'application/json'},
credentials: 'include',
})
.then(response => {console.log(response)}).catch(err => console.log(err));
}, [])
...
我也试过:
axios.get('http://localhost:8000/bills',{withCredentials: true})
.then((data) => console.log(data))
.then((result) => console.log(result))
.catch((err) => console.log('[Control Error ] ', err))
}
和
const [{ data, loading, error }, refetch] = useAxios(
'http://localhost:8000/bills',{
withCredentials: true,
headers: {'Access-Control-Allow-Origin': '*', 'Content-Type': 'application/json'
}})
Console.log 错误:
登录后,我在“网络”选项卡中看到了这个:
但是当我想访问列表时:
===更新===
所以问题的原因是没有在请求中传递 httpOnly cookie header。这是我正在使用的中间件的日志:
token undefined
req headers auth undefined
req headers {
host: 'localhost:8000',
connection: 'keep-alive',
'sec-ch-ua': '" Not;A Brand";v="99", "Google Chrome";v="97", "Chromium";v="97"',
'sec-ch-ua-mobile': '?0',
'user-agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/97.0.4692.99 Safari/537.36',
'sec-ch-ua-platform': '"macOS"',
'content-type': 'application/json',
accept: '*/*',
origin: 'http://localhost:3000',
'sec-fetch-site': 'same-site',
'sec-fetch-mode': 'cors',
'sec-fetch-dest': 'empty',
referer: 'http://localhost:3000/',
'accept-encoding': 'gzip, deflate, br',
'accept-language': 'en-US,en;q=0.9,hr;q=0.8,sr;q=0.7,bs;q=0.6,de;q=0.5,fr;q=0.4,it;q=0.3'
}
令牌是从 headers.authorization
中读取的,但是从 headers
的日志中它不存在,所以我的请求无法获得授权。
还是不行。
在阅读了 CORS
和 httpOnly cookies
上的所有内容后,我设法让它工作了。
首先,我删除了 sameSite
并根据 controllers/User.js
on SERVER
domain
道具
res.cookie('auth-token', token, {
httpOnly: true,
domain: 'http://localhost:3000'
})
然后我在控制台请求视图中看到一个黄色的小三角形,它表示域无效。然后我只是将 domain
更改为 origin
并且cookie出现在 headers
res.cookie('auth-token', token, {
httpOnly: true,
origin: 'http://localhost:3000',
})
cookie 不在 headers
的 Authorization
属性 中,而是在 cookie
中,所以我不得不更改 middleware.js
中的代码因为它期望格式 bearer xxyyzz
但收到 auth-token=xxyyzz
,所以现在看起来像这样:
exports.verify = (req, res, next) => {
const token = req.headers.cookie
if(!token) res.status(403).json({ error: "please provide a token" })
else {
jwt.verify(token.split("=")[1], tokenSecret, (err, value) => {
if(err) res.status(500).json({error: "failed to authenticate token"})
req.user = value.data
next()
})
}
}