【问题标题】:Unable to Retrieve Session Cookie of Express-Session and Connect-Session-Firebase无法检索 Express-Session 和 Connect-Session-Firebase 的 Session Cookie
【发布时间】:2020-08-23 18:01:32
【问题描述】:

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

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

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

我正在使用的技术列表:

  • node.js
  • 快递
  • 快速会话
  • firebase 功能
  • connect-session-firebase(也尝试过 firestore-store,对下面的代码稍作调整以匹配其基本设置。)

这是我的后端实现:

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.
  });
});

【问题讨论】:

  • 来自文档Note Session data is not saved in the cookie itself, just the session ID. Session data is **stored server-side**. github.com/expressjs/session#readme 所以可能不要使用快速会话。自己发送cookie给客户端。

标签: node.js firebase express google-cloud-functions express-session


【解决方案1】:

好的,现在一切正常。有几件事使它起作用。

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

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

更新:

所以上面修复了开发环境中的所有内容,但在我实际部署到 Google Functions 时没有。那时我遇到了一系列围绕 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 隐身窗口中工作,这让我很紧张,也许它只是在工作,因为我仍然缓存了一些我没有追踪的东西。原来它是隐身窗口的安全功能。您必须将其切换为 OFF 才能使会话正常工作:

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-06-27
    • 2017-10-28
    • 1970-01-01
    • 2019-11-04
    • 2021-04-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多