英文:
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 returnsdone(null, userObj)
./auth/login
returns the expected status.componentDidMount()
fires in App.js./auth/test
(incomponentDidMount()
) fires and this is where we checkreq.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);
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论