英文:
NodeJS google Oauth2 works perfectly, but deployment to Heroku stops google Oauth2 from working
问题
以下是您提供的代码的中文翻译:
我最近制作了一个React应用程序,利用了Google的OAuth2服务。对于我的服务器,我使用了Node.js单点登录与Google,本地主机上它工作得很完美,我可以存储会话并登录和退出。当我将这个相同的Node.js应用部署到Heroku时,我可以打开Google的单点登录页面,点击我的用户帐户,然后返回到我的应用程序。
但是,没有任何数据被返回到我的应用程序,没有用户配置文件被发送到我的应用程序。
// 这里是使用Passport.js进行Google身份验证的一部分代码
// 在本地主机上它会返回所有信息,在Heroku上却什么都没有返回
const GoogleStrategy = require("passport-google-oauth2").Strategy;
const passport = require("passport");
const GOOGLE_CLIENT_ID = "隐藏的ID.apps.googleusercontent.com";
const GOOGLE_CLIENT_SECRET = "隐藏的密钥";
passport.use(
new GoogleStrategy(
{
clientID: GOOGLE_CLIENT_ID,
clientSecret: GOOGLE_CLIENT_SECRET,
callbackURL: "/auth/google/callback",
proxy: true,
},
function (accessToken, refreshToken, profile, done) {
done(null, profile);
}
)
);
passport.serializeUser((user, done) => {
done(null, user);
});
passport.deserializeUser((user, done) => {
done(null, user);
});
我确保将我的Heroku链接添加到Google OAuth2的验证网站列表中,这部分正常工作。
我确保从本地主机正确接收我的数据,就代码而言,当未部署到Heroku时,它完美运行。
更新:以下是用于Google身份验证逻辑的额外Node.js代码:
const CLIENT_URL = "https://我的GitHubPages链接/home";
authRouter.get("/login/success", (req, res) => {
// 这里应该返回req.user,但它找不到req.user,所以失败了
if (req.user) {
res.status(200).json({
success: true,
message: "成功!",
user: req.user,
});
} else {
res.send(JSON.stringify({
success: false,
message: "请求失败!",
user: [],
}));
}
});
authRouter.get("/login/failed", (req, res) => {
res.status(401).json({
success: false,
message: "失败",
user: [],
});
});
authRouter.get("/logout", (req, res) => {
req.logout();
res.redirect(CLIENT_URL);
});
authRouter.get("/google", passport.authenticate("google", { scope: ["email"] }));
authRouter.get(
"/google/callback",
passport.authenticate("google", {
successRedirect: CLIENT_URL,
failureRedirect: "/auth/login/failed",
})
);
module.exports = authRouter;
这是Express逻辑的一部分:
const express = require('express');
const cors = require('cors');
const helmet = require('helmet');
const passport = require('passport');
const session = require('express-session');
const passportSetup = require("./Auth/passport");
const moviesRouter = require('./routes/movies');
const gamesRouter = require('./routes/games');
const booksRouter = require('./routes/books');
const authRouter = require('./routes/auth');
const app = express();
app.use(helmet());
app.use(express.json());
app.use(session({
secret: "secret",
resave: false,
saveUninitialized: true,
proxy: true,
}))
app.use(passport.initialize());
app.use(passport.session());
app.use(cors({
origin: 'https://mygithubpages.github.io',
methods: 'GET, POST, PUT, DELETE',
credentials: true,
}));
// --------------- 路由 --------------- //
app.use("/auth", authRouter);
// 其他路由
module.exports = app;
请注意,这些翻译仅包括代码的主要部分,不包括注释或其他内容。
英文:
I recently made a react app that utilized the google Oauth2 service. For my server I use nodeJS single sign on with google, on localhost it works perfectly and I'm allowed to store the sessions and log in and out. When I deploy this same nodejs app to heroku I am able to open the google single signon page, click my user account, and return to my app.
BUT, no data is being returned to my application, no user profile is being sent to my app.
const GoogleStrategy = require("passport-google-oauth2").Strategy;
const passport = require("passport");
const GOOGLE_CLIENT_ID = "HIDDEN_KEYmpt.apps.googleusercontent.com";
const GOOGLE_CLIENT_SECRET = "HIDDEN_KEY";
passport.use(
new GoogleStrategy(
{
clientID: GOOGLE_CLIENT_ID,
clientSecret: GOOGLE_CLIENT_SECRET,
callbackURL: "/auth/google/callback",
proxy: true,
},
function (accessToken, refreshToken, profile, done) {
// usually here it will finish the google authentication process
// and return profile user info, like the google account's email address, etc
// on localhost it returns all that, on heroku it returns nothing
done(null, profile);
}
)
);
passport.serializeUser((user, done) => {
done(null, user);
});
passport.deserializeUser((user, done) => {
done(null, user);
});
I made sure I added my Heroku link to the google Oauth2 list of verified websites, that works fine.
I made sure that my data was being received correctly from localhost, as far as the code is concerned, it works perfectly when not deployed to Heroku.
UPDATE: here is the extra NodeJS code for the google auth logic
const CLIENT_URL = "https://mygituhbpageslink/home";
authRouter.get("/login/success", (req, res) => {
// This is where the req.user SHOULD be returned after logging in, but it doesn't find a req.user so it fails
if (req.user) {
res.status(200).json({
success: true,
message: "SUCCESS!",
user: req.user,
});
} else {
res.send(JSON.stringify({
success: false,
message: "REQUEST FAILED!",
user: [],
}));
}
});
authRouter.get("/login/failed", (req, res) => {
res.status(401).json({
success: false,
message: "failure",
user: [],
});
});
authRouter.get("/logout", (req, res) => {
req.logout();
res.redirect(CLIENT_URL);
});
authRouter.get("/google", passport.authenticate("google", { scope: ["email"] }));
authRouter.get(
"/google/callback",
passport.authenticate("google", {
successRedirect: CLIENT_URL,
failureRedirect: "/auth/login/failed",
})
);
module.exports = authRouter;
And also here is the express logic
const express = require('express');
const cors = require('cors');
const helmet = require('helmet');
const passport = require('passport');
const session = require('express-session');
const passportSetup = require("./Auth/passport");
const moviesRouter = require('./routes/movies');
const gamesRouter = require('./routes/games');
const booksRouter = require('./routes/books');
const authRouter = require('./routes/auth');
const app = express();
app.use(helmet());
app.use(express.json());
app.use(session({
secret: "secret",
resave: false,
saveUninitialized: true,
proxy: true,
}))
app.use(passport.initialize());
app.use(passport.session());
app.use(cors({
origin: 'https://mygithubpages.github.io',
methods: 'GET, POST, PUT, DELETE',
credentials: true,
}));
// --------------- Routes --------------- //
app.use("/auth", authRouter);
// other routes
module.exports = app;
答案1
得分: 0
尝试更新这个,因为如果你将它托管在Heroku上,由于你的cookie跨站,当你从Google OAuth2.0得到回调时,cookie会设置到你的浏览器,你需要能够在前端发出请求进行身份验证时在请求头中获取这个cookie:
const app = express();
app.use(helmet());
app.use(express.json());
// 最好将CORS设置放在顶部
app.use(cors({
origin: 'https://mygithubpages.github.io',
methods: 'GET, POST, PUT, DELETE',
credentials: true,
}));
app.set('trust proxy', 1) // 你需要添加这一行
app.use(session({
secret: "secret",
resave: false,
saveUninitialized: false,
proxy: true, // 这是可选的,根据你托管的服务器不同而定,我不确定Heroku是否需要
cookie: {
secure: "auto", // 在开发环境中会设置为false,但在Heroku中会设置为true,因为是https,所以这个设置是必需的
maxAge: 10000, // 10秒用于测试
sameSite: "none", // 默认情况下,如果你处于开发模式下,这个值是false
},
}))
请注意,express-session会将会话存储在后端/数据库中,如果你不在cookie的属性中定义存储位置,express-session将默认将会话存储在MemoryStore中,这个存储方式不适用于生产环境,仅用于调试和开发,你需要使用兼容的会话存储方式。你可以查看express-session文档:https://github.com/expressjs/session
英文:
Try to update this since your cookies is cross-site if you host it on Heroku, the cookie is set to your browser when you get the callback from google Oauth2.0, you need to be able to get this cookie on your request header when you re going to do the request on the frontend to authenticate :
const app = express();
app.use(helmet());
app.use(express.json());
// is better to put the cors setting on the top
app.use(cors({
origin: 'https://mygithubpages.github.io',
methods: 'GET, POST, PUT, DELETE',
credentials: true,
}));
app.set('trust proxy', 1) // you need to add this
app.use(session({
secret: "secret",
resave: false,
saveUninitialized: false,
proxy: true, // this is optional it depend which server you host, i am not sure about Heroku if you need it or not
cookie: {
secure: "auto", // this will set to false on developement, but true on Heroku since is https so this setting is required
maxAge: 10000 // 10 sec for testing
sameSite: "none", //by default in developement this is false if you're in developement mode
},
}))
Beware express-session is storing session on the backend / database, and if you don't defined where to store it in cookie's property, express-session will store it by default in MemoryStore, and this is purposely not designed for a production environment. is meant only for debugging and developing, you will need to use a compatible session store. You can check on the express session documentation : https://github.com/expressjs/session
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论