首页 > 解决方案 > Kubernetes 中的路由之间没有恢复 NodeJS Express 会话

问题描述

我们有一个启用并启用的 NodeJSexpress服务器。我们已经连接了会话数据库,并且可以验证是否正在创建会话。我们的应用程序将没有令牌 cookie 的用户重定向到 Auth0 进行身份验证,然后他们将被重定向回我们的应用程序。它确实成功地设置了允许我们的用户登录的 ID 令牌。但是,passport auth0 策略抱怨它无法验证身份验证状态。express-sessionexpress-mysql-session/callback

'Unable to verify authorization request state.'

服务器代码如下,其他部分注释掉了。连接到会话数据库是成功的,因为我们可以看到每个请求都创建了会话。

const options = {
  database: process.env.SESSION_DB_NAME || "sessions",
  host: process.env.SESSION_DB_HOST! as string,
  password: process.env.SESSION_DB_PASSWORD! as string,
  port: parseInt(process.env.SESSION_DB_PASSWORD || "3306", 10),
  user: process.env.SESSION_DB_USER! as string,
};
const sessionStore = new MySQLStore(options);

app.use(
  session({
    cookie: {
      httpOnly: true,
      maxAge: 24 * 3600 * 1000, // 1 day
      secure: true,
    },
    resave: false,
    saveUninitialized: true,
    secret: process.env.SESSION_SECRET!,
    store: sessionStore,
  })
);

app.get("/login", (request, response, next) => {
  // if there is no session, it's a server error
  if (!request.session) {
    console.error(new Error("No session in /login"));
    return response.status(500).send("Server error: No Session");
  }

  return passport.authenticate("auth0", {
    scope: "openid email profile",
  })(request, response, next);
});

console.log("router: Auth0 Callback");
app.get("/callback", (request, response, next) => {
  const domain = request.hostname;
  console.log(request.session);

  passport.authenticate("auth0", (auth0Error, token, info) => {
    // if there was a problem authenticating
    if (auth0Error) {
      console.error(auth0Error);
      return response.status(500).send();
    }

    // ensure we have a session. The middleware should be giving us one.
    if (!request.session) {
      console.error("No session in /callback.");
      return response.status(500).send();
    }

    // if we couldn't log in
    if (!token) {
      if (info) {
        console.log(info);
        return response.status(500).send(info.message);
      }

      // redirect to the login page
      return response.status(401).send("Cannot log you in.");
    }

    // parse the token we get
    const user = jwt.decode(token);

    // if there is no valid user token, we've got bigger problems
    if (!user) {
      console.error("Token is falsey after authenticating.");
      return response.status(500).send();
    } else if (typeof user === "string") {
      console.error("Cannot decode JWT after authenticating");
      return response.status(500).send();
    }

    request.logIn(user, (logInError) => {
      // redirect to desired route
      // ...
    });
  })(request, response, next);
});

router.get("/*", (request, response, next) => {
  passport.authenticate("jwt", (authenticationError, isAuthenticated, info) => {
    // Log in successful via existing JWT
    if (isAuthenticated) {
      return next();
    }

    // handle unauthenticated situations
    // ...
  })(request, response, next);
});

我在https://github.com/auth0/passport-auth0/issues/70尝试了以下建议:

我们在 kubernetes 集群中运行服务器,使用 ClusterIP 作为入口。环境变量设置正确,我很确定。当我在本地运行它时,我没有任何问题。

什么可能导致会话无法恢复,而是随着每个请求重新创建?

标签: node.jsexpresssessionauth0

解决方案


您的问题是一年多前发布的,所以我认为您已经修复了它,但我想我会发布我的解决方案来帮助其他人。我最近遇到了同样的问题,尽管我使用的是 Apache 反向代理而不是 Kubernetes 集群。

我在另一个 SO 问题中发布了我的解决方案:https ://stackoverflow.com/a/67891167/8221175

简而言之,我的 Apache 配置缺少这些行:

RequestHeader set X-Forwarded-Proto expr=%{REQUEST_SCHEME}
RequestHeader set X-Forwarded-SSL expr=%{HTTPS}

ProxyPass / http://localhost:8001/
ProxyPassReverse / http://localhost:8001/

这与 express 的其他会话/cookie 配置(请参阅 SO 链接)一起修复了它。我的会话现在仍然存在,我不再有这个问题。

对于那些对为什么“无法验证授权请求状态”感兴趣的人。消息已发出,请在此 GitHub 问题中查看我的答案:https ://github.com/auth0/passport-auth0/issues/89#issuecomment-856971807


推荐阅读