passport-local的deserializeUser()在部署期间未被调用。在开发中正常工作。

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

passport-local's deserializeUser() is not called during deployment. Works fine in development

问题

是的,我知道类组件已经过时,成功部署后将其更新为功能性组件/钩子。

我已经使用Passport的本地策略和ES6实现了一个MERN(MongoDB、Express、React和Node.js)应用程序。

预期:
用户登录时,他们发送请求到“/auth/login”路由,该路由使用passport.authenticate()方法进行身份验证。如果身份验证成功,服务器向客户端发送“success”响应。

一旦客户端收到“success”响应,App.js组件的componentDidMount()方法被调用。在这个方法中,客户端发送请求到“/auth/test”路由,以检查用户是否经过身份验证,使用req.isAuthenticated()

如果用户已经通过身份验证,服务器将返回用户对象,然后将其字符串化并存储在客户端的本地存储中,以表示用户已登录。

开发模式:
在开发中,我将客户端放在一个端口,API放在另一个端口。一切都正常

当前情况:
部署后,我通过Render.com托管客户端和API。

  • 确保Render中所有环境变量都正确设置。
  • 根据远离localhost的新客户端和API URL更新任何baseURL
  • 利用console.log确保流程符合预期(但实际情况并非如此,见下文)。

当前流程:

  • 使用正确的ID调用serializeUser()
  • 调用localStrategy,找到正确的用户和密码,返回done(null, userObj)
  • /auth/login返回预期状态。
  • 在App.js中触发componentDidMount()
  • /auth/test(在componentDidMount()中)触发,这是我们检查req.isAuthenticated的地方。

CORS注意事项:

  • 没有关于CORS的错误/警告。
  • 从客户端使用credentials: "include"选择加入。
  • 从服务器使用以下方式选择加入:
const allowedOrigins =
    process.env.NODE_ENV === "development"
      ? "http://localhost:3000"
      : "https://my-client.onrender.com";
const corsOptions = {
    origin: allowedOrigins,
    credentials: true,
};
app.use(cors(corsOptions));

问题:
req.isAuthenticated()返回false,因为req未定义。

我观察到的情况(通过控制台日志):

  • deserializeUser()从未被调用(在开发中正常调用)。
  • 部署期间未设置Cookie(在开发中设置正常)。
  • 在API日志中没有错误。
  • 在控制台上没有错误。

谢谢。

客户端

/auth/login

const url = baseURL + "/auth/login?username=" + id + "&password=" + pw;
const res = await fetch(url, {
    method: "POST",
    credentials: "include",
});

/auth/test

fetch(baseURL + "/auth/test", {
    credentials: "include",
})

API

/auth/login 路由

authRoute.post("/auth/login", passport.authenticate("local"),
    (req, res) => {
        res.status(200).send("Login successful");
    },

/auth/test 路由

authRoute.get("/auth/test", (req, res) => {
    const isAuth = req.isAuthenticated(); // 问题:返回false,因为req未定义
// 等等。

passportConfig

app
    .use(
        session({
            secret: process.env.SESSION_SECRET,
            resave: false,
            saveUninitialized: true,
            cookie: {
                secure: process.env.NODE_ENV === "development" ? false : true,
                httpOnly: process.env.NODE_ENV === "development" ? false : true,
                sameSite: process.env.NODE_ENV === "development" ? "" : "none", // 如果使用CORS,则设置
                domain: process.env.NODE_ENV === "development" ? "" : ".onrender.com",
                path: "/",
                maxAge: 1000 * 60 * 5,
            }, // 5分钟
        })
    )
    .use(passport.initialize())
    .use(passport.session());

提前致谢!

英文:

(Yes, I know class components are outdated, updating to functional/hooks after successful deployment)

I have implemented a MERN (MongoDB, Express, React, and Node.js) application with authentication using Passport's local strategy and ES6.

Expected:
When the user logs in, they send a request to the "/auth/login" route, which is authenticated using the passport.authenticate() method. If the authentication is successful, the server sends a "success" response back to the client.

Once the client receives the "success" response, the App.js component's componentDidMount() method is called. In this method, the client sends a request to the "/auth/test" route to check if the user is authenticated using req.isAuthenticated().

If the user is authenticated, the server sends back the user object, which is then stringified and stored in the client's local storage to indicate that the user is logged in.

Development Mode:
For development, I am having the client on one port and the API on another. Everything works fine.

Currently:
After deployment, I am hosting both the client and API through Render.com.

  • I have ensured that all the environment variables are set properly within Render
  • I have updated any baseURL to match the new client and API URLs respectively as I move away from localhost.
  • I have put console.log's everywhere to ensure the flow is as expected (it's not. See below).

Current Flow:

  • serializeUser() is called with the correct id.
  • localStrategy is called and it finds the correct user and password and returns done(null, userObj).
  • /auth/login returns the expected status.
  • componentDidMount() fires in App.js.
  • /auth/test (in componentDidMount()) fires and this is where we check req.isAuthenticated.

Notes on CORS:

  • I am not receiving any errors/warnings about CORS
  • I am opting in from the client with credentials: "include"
  • I am opting in from the server with
    const allowedOrigins =
      process.env.NODE_ENV === "development"
        ? "http://localhost:3000"
        : "https://my-client.onrender.com";
    const corsOptions = {
      origin: allowedOrigins,
      credentials: true,
    };
    app.use(cors(corsOptions));
    

Problem:
req.isAuthenticated() returns false because req is undefined.

What I've witnessed (through console logs):

  • deserializeUser() is never called (Gets called fine in dev)
  • Cookies are never set during deployment (Cookie sets fine in dev)
  • There are no errors within the API logs
  • I get no errors on the console

Thank you

Client

/auth/login

    const url = baseURL + "/auth/login?username=" + id + "&password=" + pw;
    const res = await fetch(url, {
      method: "POST",
      credentials: "include",
    });

/auth/test

     fetch(baseURL + "/auth/test", {
        credentials: "include",
      })

API

/auth/login Route

authRoute.post("/auth/login",passport.authenticate("local"),
  (req, res) => {
    res.status(200).send("Login successful");
  },

/auth/test Route

authRoute.get("/auth/test", (req, res) => {
  const isAuth = req.isAuthenticated(); // PROBLEM: Returns false because req is undefined
// etc.

passportConfig

  app
    .use(
      session({
        secret: process.env.SESSION_SECRET,
        resave: false,
        saveUninitialized: true,
        cookie: {
          secure: process.env.NODE_ENV === "development" ? false : true,
          httpOnly: process.env.NODE_ENV === "development" ? false : true,
          sameSite: process.env.NODE_ENV === "development" ? "" : "none", // Set if using CORS
          domain: process.env.NODE_ENV === "development" ? "" : ".onrender.com",
          path: "/",
          maxAge: 1000 * 60 * 5,
        }, // 5 minutes
      })
    )

    .use(passport.initialize())
    .use(passport.session());

Thanks in advance!

答案1

得分: 1

在你的配置中,有一行看起来有问题,特别是在你的域名前面的这个 .

domain: process.env.NODE_ENV === "development" ? "" : ".onrender.com" 行。

我建议完全删除这行。你也可以将它改为只是 onrender.com

如果远程服务器通过非HTTP中介传递请求,Express也 不会设置cookie。你可以告诉它信任这个代理:

if (process.env.NODE_ENV === 'production') {
  app.set('trust proxy', 1);
}
英文:

One thing that looks suspect in your configuration is this line, specifically the . preceding your domain:

domain: process.env.NODE_ENV === "development" ? "" : ".onrender.com", line.

I would drop that line entirely. You could also change it to just onrender.com.

Express will also not set a cookie if the remote server is passing the request through a non-http intermediary. You can tell it to trust this proxy:

if (process.env.NODE_ENV === 'production') {
  app.set('trust proxy', 1);
}

huangapple
  • 本文由 发表于 2023年2月24日 10:58:04
  • 转载请务必保留本文链接:https://go.coder-hub.com/75552243.html
匿名

发表评论

匿名网友

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

确定