[英]Cookie not set, even though it is in response headers. Using express-session cookies
Problem:问题:
Trying to set the cookie on login using express-session
, but think I'm missing something obvious.尝试使用
express-session
在登录时设置 cookie,但认为我遗漏了一些明显的东西。 The response to the login POST request includes Set-Cookie.登录 POST 请求的响应包括 Set-Cookie。 I've also set the
Access-Control-Allow-Origin
and Access-Control-Allow-Headers
to wildcards as shown here: https://i.stack.imgur.com/XS0Zv.png我还将
Access-Control-Allow-Origin
和Access-Control-Allow-Headers
设置为通配符,如下所示: https://i.stack.imgur.com/XS0Zv.png
But we see that in the browser storage (tried with Firefox and Chrome) there is nothing.但我们看到在浏览器存储中(尝试使用 Firefox 和 Chrome)没有任何内容。 As shown here
如此处所示
I'm currently setting my express-session as follows (refer to end of post for full code. Adding snippet for easier read):我目前正在按如下方式设置我的快速会话(请参阅帖子末尾的完整代码。添加代码片段以便于阅读):
app.use(session({
genid: () => { return uuidv4(); },
store: new MongoStore({ mongooseConnection: mongoose.connection }),
secret: process.env.SESSION_SECRET,
resave: false,
saveUninitialized: true,
cookie: {
httpOnly: true,
secure: false,
sameSite: true,
}
})
);
Then after I've verified the user is getting logged in, I try to set the userId via:然后在我验证用户正在登录后,我尝试通过以下方式设置 userId:
req.session.userId = user.id;
Possibly Relevant Info可能相关信息
localhost:8000
via: app.listen(8000);
app.listen(8000);
在localhost:8000
上运行;http://localhost:3000/
http://localhost:3000/
上运行Things I've tried so far:到目前为止我尝试过的事情:
resave
, saveUnitialized
. resave
和saveUnitialized
的不同组合。cookie
parameter.cookie
参数。Please advise!请指教! Even ideas on how to debug this or what other things I can look at would be immensely helpful!
甚至关于如何调试这个或我可以查看的其他内容的想法也会非常有帮助!
Relevant Code相关代码
app.js应用程序.js
const express = require('express');
const { graphqlHTTP } = require('express-graphql');
const mongoose = require('mongoose');
const session = require('express-session');
const MongoStore = require('connect-mongo')(session);
const {v4: uuidv4} = require('uuid');
const graphqlSchema = require('./graphql/schema/index');
const graphqlResolvers = require('./graphql/resolvers/index');
const app = express();
const path = '/graphql';
app.use(bodyParser.json());
app.use((req, res, next) => {
res.setHeader('Access-Control-Allow-Origin', '*');
res.setHeader('Access-Control-Allow-Methods', 'POST,GET,OPTIONS');
res.setHeader('Access-Control-Allow-Headers', '*');
if (req.method === 'OPTIONS') {
return res.sendStatus(200);
}
next();
});
mongoose
.connect(`mongodb+srv://${process.env.MONGO_USER}:${process.env.MONGO_PASSWORD}@cluster0.ccz92.mongodb.net/${process.env.MONGO_DB}?retryWrites=true&w=majority`,
{ useNewUrlParser: true, useUnifiedTopology: true, useFindAndModify: false }
)
.then(() => {
app.use(session({
genid: () => { return uuidv4(); },
store: new MongoStore({ mongooseConnection: mongoose.connection }),
secret: process.env.SESSION_SECRET,
resave: false,
saveUninitialized: true,
cookie: {
httpOnly: true,
secure: false,
sameSite: true,
}
})
);
app.use(path, graphqlHTTP({
schema: graphqlSchema,
rootValue: graphqlResolvers,
graphiql: true,
}));
app.listen(8000);
})
.catch(err => {
console.log(err);
});
graphql/resolvers/auth.js graphql/resolvers/auth.js
const argon2 = require('argon2');
const jwt = require('jsonwebtoken');
const User = require('../../models/user');
module.exports = {
createUser: async args => {
try {
const existingUser = await User.findOne({
email: args.userInput.email
});
if (existingUser) {
throw new Error('User exists already.');
}
const hashedPassword = await argon2.hash(
args.userInput.password,
12
);
const user = new User({
email: args.userInput.email,
password: hashedPassword,
loggedIn: true
});
const result = await user.save();
const token = jwt.sign(
{ userId: result.id, email: result.email },
process.env.JWT_KEY,
{ expiresIn: '1h' }
);
return {
userId: result.id,
token: token,
tokenExpiration: 1
};
} catch (err) {
console.log("error in resolvers/auth.js");
throw err;
}
},
login: async (args, req) => {
const { userId } = req.session;
if (userId) {
console.log("found req.session");
return User.findOne({ _id: userId });
}
console.log("looking for user with ", args.userInput.email);
const user = await User.findOne({ email: args.userInput.email });
console.log("found user");
if (!user) {
throw new Error("User does not exist!");
}
user.loggedIn = true;
user.save();
const isEqual = await argon2.verify(user.password, args.userInput.password);
if (!isEqual) {
throw new Error ("Password is incorrect!");
}
console.log("setting session.userId");
req.session.userId = user.id;
return { ...user._doc, password: null};
},
logout: async (args, req) => {
if (!req.isAuth) {
throw new Error('Unauthenticated');
}
try {
const result = await User.findOneAndUpdate(
{ _id: req.userId },
{ loggedIn: false },
{ new: true },
);
return { ...result._doc, password: null };
} catch (err) {
console.log("logout error", err);
throw(err);
}
},
};
So it turned out to be a CORS issue.所以原来是 CORS 问题。 I didn't realize that the port would mean a different origin.
我没有意识到这个港口意味着不同的起源。 In this case my client is at 3000 and my server is at 8000.
在这种情况下,我的客户端位于 3000,而我的服务器位于 8000。
Given the CORS nature, in the client I need to include credentials
(cookies, authorization headers, or TLS client certificates) when I'm fetching:鉴于 CORS 的性质,在获取时我需要在客户端中包含
credentials
(cookie、授权标头或 TLS 客户端证书):
fetch(config.url.API_URL, {
method: 'POST',
body: JSON.stringify(requestBody),
headers: {
'Content-Type': 'application/json'
},
credentials: "include",
})
This will tell the user agent to always send cookies.这将告诉用户代理始终发送 cookies。
Then serverside I need to set Access-Control-Allow-Credentials
to be true as such:然后服务器端我需要将
Access-Control-Allow-Credentials
设置为 true,如下所示:
res.setHeader('Access-Control-Allow-Credentials', true);
This will allow the browser to expose the response (which has the cookie) to the frontend Javascript code.这将允许浏览器向前端 Javascript 代码公开响应(具有 cookie)。
Since we are using credentials, we will need to specify Access-Control-Allow-Headers
and Access-Control-Allow-Origin
由于我们使用凭据,我们需要指定
Access-Control-Allow-Headers
和Access-Control-Allow-Origin
res.setHeader('Access-Control-Allow-Headers', 'Origin, X-Requested-With, Content-Type, Accept')
res.setHeader('Access-Control-Allow-Origin', 'http://localhost:3000');
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.