NodeJS的Google OAuth2在本地运行正常,但部署到Heroku后,Google OAuth2不再工作。

huangapple go评论69阅读模式
英文:

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

huangapple
  • 本文由 发表于 2023年1月5日 08:34:58
  • 转载请务必保留本文链接:https://go.coder-hub.com/75012752.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定