这个问题一直让我抓狂。我在前端使用 React 和 Apollo (GraphQL),并在后端使用 Passport.js 和 Express
cookie-session
进行身份验证。在桌面上的任何浏览器(尚未测试 safari)上,一切都可以完美运行,但是 cookie 不会保存在 IOS 上,并且用户无法登录。仅当使用 passport-local
并且浏览器还没有 cookie 时才会出现此问题。如果我使用 passport-google
或 passport-facebook
登录,它可以工作,然后如果我注销并再次使用 passport-local
,它也可以工作,即使是不同的用户。另外,如果我进入设置并关闭 IOS Safari 的“防止跨站点跟踪”,它第一次就能工作,但是如果我想将其用作 PWA,则无法将其关闭。
我的快速设置如下所示(省略所有导入):
app.use(
cookieSession({
maxAge: 24 * 60 * 60 * 1000 * 30,
keys: [process.env.COOKIE_KEY],
overwrite: true
})
);
app.use(passport.initialize());
app.use(passport.session());
app.use(flash());
const whitelist = [
"https://toomanylists.com",
"https://www.toomanylists.com"
];
app.use(
cors({
origin: (origin, callback) => {
console.log(origin);
if (whitelist.indexOf(origin) !== -1 || !origin) {
callback(null, true);
} else {
callback(new Error("blocked by CORS"));
}
},
credentials: true
})
);
app.options("*", cors());
app.use("/auth", authRoutes);
mongoose.connect(process.env.MONGODB_URI);
mongoose.connection.once("open", () => {
console.log("Connected to Database");
});
const authCheck = (req, res, next) => {
if (!req.user) {
res.redirect("https://toomanylists.com");
} else {
next();
}
};
app.use(
"/graphql",
authCheck,
graphqlHTTP({
schema: schema,
graphiql: true
})
);
我的登录路线:
router.post("/login", jsonParser, (req, res, next) => {
passport.authenticate("user-login", (err, user, info) => {
if (err) {
return next(err);
}
if (!user) {
return res.status(401).send(JSON.stringify(info));
}
req.logIn(user, function(err) {
if (err) {
return next(err);
}
return res.status(200).send(JSON.stringify(info));
});
})(req, res, next);
});
在 React 中,我使用 fetch API 发送请求:
fetch(<my_server_url/login>, {
method: "POST",
credentials: "include",
headers: {
Accept: "application/json",
"Content-Type": "application/json"
},
body: JSON.stringify(this.state)
}).then(response => {
//if fails alerts with custom message
if (response.status === 401) {
response.json().then(json => {
alert(json.message);
});
} //if successful refresh with cookies
if (response.status === 200) {
window.location.reload(false);
}
});
另一个可能相关的问题是,如果我将
{secure: true}
选项添加到 cookie-session
,它根本不起作用,即使我通过 AWS 使用有效的 SSL 证书,其中前端托管在 S3 存储桶中。后端是heroku,也是https。如果该网站可以帮助任何人查看并尝试使用它并检查开发工具,则该网站已上线。我还没有在 Android 或 ipad 上测试过。 https://toomanylists.com
无论如何,我认为这是一个不太可能的事情,但我希望也许有一些我遗漏的简单的东西,并且这不是我的设置和它们阻止cookie的无法解决的IOS问题(这是IOS 12中的新功能吗?)。另外,有谁知道这是否也是使用 JWT 的问题以及这是否是验证用户身份的安全方法?
可能有一千种解决方案,但这是我的。
我需要在开发中使用 CORS,但在生产中不需要。下面的两组代码都是 CORS 所需要的(我认为),但我只检查了第一组代码以查看我的环境变量
use_cors
是否为真。一旦我通过在它们周围放置 if 语句来删除生产中与 CORS 相关的标头(该变量在产品中设置为 false),问题就解决了。
长话短说:无论您是否使用 CORS,请确保您的标头正确。
//Set up CORS in development, but not in production
if (process.env.USE_CORS === 'true') {
app.use(
cors({
origin: process.env.CLIENT,
methods: ['GET', 'POST', 'PUT'],
credentials: true
})
)
}
//Set CORS Headers in development, but not in production
if (process.env.SET_CORS_HEADERS === 'true') {
app.use(function (req, res, next) {
res.header('Access-Control-Allow-Credentials', true)
res.header('Access-Control-Allow-Origin', req.headers.origin)
res.header('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE')
res.header('Access-Control-Allow-Headers', 'X-Requested-With, X-HTTP-Method-Override, Content-Type, Accept')
next()
})
}