【问题标题】:Session cookie is not set in browser浏览器中未设置会话 cookie
【发布时间】:2019-06-08 20:32:57
【问题描述】:

我在自定义 Next.js 服务器上运行前端客户端,该服务器使用 apollo 客户端获取数据。 我的后端是带有 prisma 的 graphql-yoga,它使用了 express-session。

我在为我的客户端和后端选择正确的 CORS 设置时遇到问题,因此 cookie 可以在浏览器中正确设置,尤其是在 heroku 上。

目前我正在使用 apollo-client 选项从客户端发送 graphql 请求 credentials: "include" 但也尝试过"same-origin" 没有更好的结果。

我可以在 Set-Cookie 标头和 devTools/application/cookies 中看到来自后端的 cookie 客户端响应。但是这个 cookie 对浏览器是透明的,并且在刷新时会丢失。

话虽如此,我还尝试对apollo client 实施一些后件作为apolloLink,这将拦截来自response.headers 的cookie,但它是空的。

到目前为止,我正在考虑寻求这两种解决问题的途径。

(我只实现了 CORS,因为浏览器阻止在没有它的情况下获取数据。)

客户

客户端的 ApolloClient 配置:

const httpLink = new HttpLink({
  credentials: "include",
  uri: BACKEND_ENDPOINT,
});

客户端 CORS 使用和配置:

 app
    .prepare()
    .then(() => {
      const server = express()
        .use(cors(corsOptions))
        .options("*", cors(corsOptions))
        .set("trust proxy", 1);

...here goes rest of implementation

const corsOptions = {
  origin: [process.env.BACKEND_ENDPOINT, process.env.HEROKU_CORS_URL],
  credentials: true,
  allowedHeaders: ["Content-Type", "Authorization", "X-Requested-With", "X-Forwarded-Proto", "Cookie", "Set-Cookie", '*'],
  methods: "GET,POST",
  optionsSuccessStatus: 200
};

我尝试从 apolloClient 中的响应中获取标头(但标头为空,之后未获取数据):

const middlewareLink = new ApolloLink((operation, forward) => {
   return forward(operation).map(response => {
     const context = operation.getContext();

     const {response: {headers}} = context;
     if (headers) {
       const cookie = response.headers.get("set-cookie");
       if (cookie) {
         //set cookie here
       }
     }
     return response;
   });

 });

后台

CORS 实现(请记住,这是 gql-yoga,所以我需要先从中公开 express)

server.express
  .use(cors(corsOptions))
  .options("*", cors())
  .set("trust proxy", 1);

...here goes rest of implementation
const corsOptions = {
  origin: [process.env.CLIENT_URL_DEV, process.env.CLIENT_URL_PROD, process.env.HEROKU_CORS_URL],
  credentials: true,
  allowedHeaders: ["Content-Type", "Authorization", "X-Requested-With", "X-Forwarded-Proto", "Cookie", "Set-Cookie"],
  exposedHeaders: ["Content-Type", "Authorization", "X-Requested-With", "X-Forwarded-Proto", "Cookie", "Set-Cookie"],
  methods: "GET,HEAD,PUT,PATCH,POST,OPTIONS",
  optionsSuccessStatus: 200
};

会话设置,存储为connect-redis

server.express
  .use(
    session({
      store: store,
      genid: () => uuidv4(v4options),
      name: process.env.SESSION_NAME,
      secret: process.env.SESSION_SECRET,
      resave: true,
      rolling: true,
      saveUninitialized: false,
      sameSite: false,
      proxy: STAGE,
      unset: "destroy",
      cookie: {
        httpOnly: true,
        path: "/",
        secure: STAGE,
        maxAge: STAGE ? TTL_PROD : TTL_DEV
      }
    })
  )  

我希望在身份验证后在客户端上设置会话 cookie。

实际结果: Cookie 仅在 Set-Cookie 响应标头中可见,但对浏览器是透明的,既不持久也不设置(在刷新或页面更改时丢失)。有趣的是,我仍然可以发出经过身份验证的数据请求。

【问题讨论】:

  • 你解决了吗?
  • 很遗憾,不 - 我们出于这个愚蠢的原因从 next.js 切换到 cra
  • 我设法通过在 heroku 的前端和后端使用自定义域来解决它

标签: heroku cross-domain session-cookies next.js apollo-client


【解决方案1】:

这可能不是 CORS 问题,它看起来像第三方 cookie 问题。

不同浏览器的行为可能不同,所以我建议测试几个。 Firefox(从 77 版开始)似乎限制较少。在 Chrome(从版本 83 开始)中,当第三方 cookie 被阻止时,URL 栏的最右侧有一个指示符。您可以通过为当前网站创建例外来确认第三方 cookie 是否是问题的原因。

假设您当前的设置如下:

frontend.com
backend.herokuapp.com

为后端使用自定义域作为前端的子域可以解决您的问题:

frontend.com
api.frontend.com 

以下设置不起作用,因为 herokuapp.com 包含在 Mozilla 基金会的公共后缀列表中:

frontend.herokuapp.com
backend.herokuapp.com

More details on Heroku.

【讨论】:

    猜你喜欢
    • 2019-01-30
    • 2018-10-26
    • 2012-11-07
    • 1970-01-01
    • 2021-09-30
    • 2019-07-25
    • 2023-03-16
    • 1970-01-01
    相关资源
    最近更新 更多