未在浏览器中设置会话Cookie

时间:2019-01-14 20:16:11

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

我有运行在自定义Next.js服务器上的前端客户端,该服务器正在使用apollo客户端获取数据。 我的后端是带有expressa会话的带有pyramida的graphql-yoga。

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

当前,我正在从带有apollo客户端的客户端发送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;
   });

 });

BACKEND

CORS实现(记住是gql-yoga,所以我需要先公开其中的内容)

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响应标头中可见,但对浏览器是透明的,并且不持久或未设置(刷新或页面更改时丢失)。有趣的是,我仍然可以发出经过身份验证的数据请求。

1 个答案:

答案 0 :(得分:1)

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

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

假设您当前的设置如下:

F5* executes the current file.

F9* executes the currently highlighted chunk of code

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

frontend.com
backend.herokuapp.com

以下设置无效,因为frontend.com api.frontend.com 已包含在Mozilla Foundation的公共后缀列表中:

herokuapp.com

More details on Heroku