无法检索 Express-Session 和 Connect-Session-Firebase 的 Session Cookie

Unable to Retrieve Session Cookie of Express-Session and Connect-Session-Firebase

我正在尝试完成 oauth-1 握手。我的后端托管在 Google Functions 上。我将快速浏览流程以获得上下文:

  1. 用户在前端点击以将 Etsy 连接添加到我的应用程序。然后,我的前端联系后端中的适当端点以启动此过程。
  2. 我的后端从 Etsy 请求一个令牌,我收到一个令牌、一个秘密和一个 url 将用户重定向到,以便他们可以登录。我尝试将令牌和秘密存储在一个 session cookie 供以后使用——因为我使用的是 Google 函数,后端本身不会“持久化”,所以我试图存储这些值以便在下一个 execution/stage. (注意:在请求令牌时,我提供了一个回调 URL,它将在用户登录时联系。)
  3. 我的前端从第 2 步收到 url 并将用户重定向到那里登录。
  4. 用户通过该登录批准,并调用回调 URL。这包括验证器。然后我必须使用步骤 2 中的验证器和令牌和秘密获取 accessToken。虽然我认为这些将在 session 中检索,但它们都是未定义的,因此我对 accessToken 的请求失败了。

在我看来,每次调用都会创建一个新的 session,无论是否已经存在 session。如果我在第 1 步和第 2 步检查 session,它们的时间戳是不同的,这让我认为第 2 步不是从第 1 步检索 session,而是创建一个新的——很可能是因为我的表现 app.use(session).

我使用的技术列表:

这是我的后端实现:

const url = require('url');
const functions = require('firebase-functions');
const admin = require('firebase-admin');
const express = require("express");
const app = express();
const cors = require("cors")
const session = require('express-session')
const FirebaseStore = require('connect-session-firebase')(session);

// Etsy OAuth
// For Etsy OAuth
const etsyjs = require('etsy-js');
const client = etsyjs.client({
  key: process.env.ETSY_KEY,
  secret: process.env.ESTY_SECRET,
  callbackURL: '<location>/authorize'
});

const ref = admin.initializeApp({
  credential: admin.credential.cert(json), //json retrieved and put here
  databaseURL: 'https://<app>.firebaseio.com'
});

app.use(cors())
app.use(session({
    store: new FirebaseStore({
         database: ref.database(),
    }),
    secret: 'My secret',
    resave: true,
    saveUninitialized: true,
    name: '__session',
    cookie: {
      maxAge : 60000,
        secure: false,
        httpOnly: false 
     }
    }
));

// Step 1 for backend of OAuth
app.get('/begin-oauth', (req, res) => {
  res.setHeader('Cache-Control', 'private'); // I read somewhere this needs to be set, but I am not seeing a difference either way with it.

  return client.requestToken((err, response) => {
    if (err) {
      return console.log(err);
    }

    req.session.token = response.token;
    req.session.sec = response.tokenSecret;

    res.status('200').send(response) // returning url to send the user there via frontend.
  });
});

// Step 2 for backend of OAuth
app.get('/authorize', (req, res) => {
  
  let query, verifier;
  query = url.parse(req.url, true).query;
  verifier = query.oauth_verifier;

  // session at this point should have token and sec stored from before but are not present.
  return client.accessToken(req.session.token, req.session.sec, verifier, (err, response) => {
    if (err) {
      console.log(err);
    }
    req.session.token = response.token;
    req.session.sec = response.tokenSecret;

    // Finish up.
  });
});

好的,现在一切正常。有几件事让它发挥作用。

  1. 在后端调用中包含凭据,现在看起来像这样:
return await fetch(url, {
    method: 'GET',
    headers: {
      'Content-Type': 'application/json',
    },
    credentials: 'include',
  }).then(...)
  1. 正在将凭据添加到 cors 设置 server-side。所以现在看起来像这样:
var corsOptions = {
  credentials: true,
  origin: true
}

app.use(cors(corsOptions))
  1. 这些仍然没有完全解决问题。最终解决问题的是我从浏览器中清除了缓存。我相信这是真正解决问题的方法!尝试这个简单的事情花了多长时间绝对是痛苦的。

更新:

所以上面修复了开发环境中的所有内容,但当我实际部署到 Google 函数时却没有。那时我遇到了一系列围绕 cors 的新问题。这是我收到的错误消息:

这是我为解决此问题所做的更改:

app.use(function(req, res, next) {
  var allowedOrigins = ['http://localhost:3000', 'http://localhost:5000', 'https://www.<site>.com', 'https://<app-location>.cloudfunctions.net', 'https://<app>.firebaseio.com']
  var origin = req.headers.origin;
  functions.logger.log('Checking headers:')
  functions.logger.log(origin)
  functions.logger.log(req.headers)
  if(allowedOrigins.indexOf(origin) > -1){
       res.setHeader('Access-Control-Allow-Origin', origin);
  }

  res.header('Access-Control-Allow-Methods', 'GET, OPTIONS');
  res.header('Access-Control-Allow-Headers', 'Content-Type, Authorization');
  res.header('Access-Control-Allow-Credentials', true);
  return next();
});

并且我将 cookie 更新为:

cookie: {
  maxAge: 30*24*60*60*1000, 
  secure: true, 
  httpOnly: false, 
  sameSite: 'none'
}

^ 特别是,我设置了 secure: truesameSite: 'none'

更新 2:

有了上面的内容,我让它以部署的形式工作,但它不能在 Chrome 隐身 window 中工作,这让我很紧张,也许它能工作只是因为我仍然缓存了一些东西我没有追踪。原来这是 incognito windows 的安全功能。您必须将其关闭才能使会话正常工作: