NodeJS 当请求包含授权头时,是否阻止Expressjs创建会话?

5rgfhyps  于 2023-06-22  发布在  Node.js
关注(0)|答案(4)|浏览(118)

我有一个API,可以使用浏览器调用,其中请求是事务性的,并且有一个会话,或者直接调用,例如。使用curl,其中请求是原子的。浏览器请求必须首先进行身份验证,然后使用快速会话(connect.sid)进行后续授权,直接API调用使用标头:Authorization: "SOMETOKEN",它必须为每个请求发送。
我遇到的问题是,因为我使用同一个Web服务器来服务原子流量和事务流量,所以Express不必要地为每个API调用提供一个会话。每个响应都包含一个Set-Cookie,所有这些会话都填满了我的会话存储。因此:当请求包含Authorization头时,如何阻止Express在内存存储(Redis)中输入新的sess密钥?
注意,我知道一个更经典的方法是拥有一个单独的API服务器和一个单独的WEB服务器,但为什么不在一台机器上运行这两个服务器呢?对我来说,区别在于API提供数据,WEB提供视图,但除此之外,它们都是同一个应用程序的一部分。我只是碰巧也允许用户直接访问他们的数据,而不是强迫他们使用我的界面。

### Express Config

module.exports = function(app, exp, sessionStore, cookieParser, passport, flash) {
  app.configure(function() {
    // Templates
    app.set('views', ERNEST.root + '/server/views');
    app.set('view engine', 'jade');
    app.set('view options', { doctype : 'html', pretty : true });
    
    // Allow large files to be uploaded (default limit is 100mb)
    app.use(exp.limit('1000mb'));
    
    // Faux putting and deleting
    app.use(exp.methodOverride());
    
    // Static content
    app.use(exp.static(ERNEST.root + '/server'));
    app.use(exp.static(ERNEST.root + '/public'));
    
    // Handle favicon
    app.use(exp.favicon());
    
    // For uploads
    app.use(exp.bodyParser({keepExtensions: true}));
            
    // Configure cookie parsing
    if (cookieParser)   app.use(cookieParser);
    else app.use(exp.cookieParser());
    
    // Where to store the session
    var session_options = { 'secret': "and she put them on the mantlepiece" };
    if (sessionStore) session_options.store = sessionStore;
    app.use(exp.session(session_options));
    
    // Rememberance
    app.use(function (req, res, next) {
      if (req.method == 'POST' && req.url == '/authenticate') {
        if ( req.body.rememberme === 'on' ) {
          req.session.cookie.maxAge = 2592000000; // 30*24*60*60*1000 Rememeber 'me' for 30 days
        } else {
          req.session.cookie.expires = false;
        }
      }
      next();
    });
            
    // PassportJS
    if (passport){
      app.use(flash());
      app.use(passport.initialize());
      app.use(passport.session());
    }
  });
};

示例路由:

app.get('/status/past_week', MID.ensureAuthenticated, MID.markStart, function(req, res) {
  WEB.getStatus('week', function(err, statuses){
    if (err) res.send(500, err);
    else res.send(200, statuses);
  });
});

授权中间件

MID.ensureAuthenticated = function(req, res, next) {
  if (req.isAuthenticated()) return next();
  else {
    isAuthorised(req, function(err, authorised) {
      if (err) return res.redirect('/');
      else if (authorised) return next();
      else return res.redirect('/');
    });
  }
    
  function isAuthorised(req, callback) {
    var authHeader = req.headers.authorization;
    if (authHeader) {
      // Has header, verify it
      var unencoded = new Buffer(authHeader, 'base64').toString();
      var formatted = unencoded.toString().trim();
      ACCOUNT.verifyAuth(formatted, callback); // verifyAuth callbacks next() when successful
    } else callback(null, false); // No Authorised header
  }
};
ohfgkhjo

ohfgkhjo1#

试试这个:

var sessionMiddleware = exp.session( session_options );

app.use(function(req, res, next) {
  if (req.headers.authorization) {
    return next();
  }
  return sessionMiddleware(req, res, next);
});
uwopmtnx

uwopmtnx2#

看起来您需要编写自己的会话中间件。Here's an example。如果你可以创建一个单独的子域,比如说,www.example.com用于浏览器会话,app.example.com用于直接访问它,那么你应该能够几乎完全使用链接的方法,只是不要为app.example.com请求启动会话。这可能是最直接的方法,调用通过该方法指示它打算进行身份验证的方法,任何偏离该方法的行为都是错误的。
否则,您将不得不在中间件中检测身份验证令牌,并且在找到它时不启动会话。

c0vxltue

c0vxltue3#

减少会话存储中存储的会话数量的另一种方法是将默认maxAge设置为较低的值。然后,当您实际需要存储更长时间的会话时,例如用户登录后,您可以设置req.session.cookie.expires = null;。另外,不要忘记在用户注销时将会话过期时间设置为较低的值。
下面是一个例子:

// set default to something low
app.use(session({
  resave: true,
  saveUninitialized: true,
  cookie: {
    maxAge: 5 * 60 * 1000 // 5 minutes
  },
  secret: secrets.sessionSecret,
  store: new MongoStore({
    url: yourUrl,
    auto_reconnect: true
  })
}));

// on successful login, 
// set expiration to null or something longer than default
var time = 14 * 24 * 3600000; //2 weeks
req.session.cookie.maxAge = time;
req.session.cookie.expires = new Date(Date.now() + time);
req.session.touch();

// on logout, reset expiration to something low  
var time = 5 * 60 * 1000; // 5 minutes
req.session.cookie.maxAge = time; //2 weeks
req.session.cookie.expires = new Date(Date.now() + time);
req.session.touch();

这在远程监控应用时特别有用,因为如果监控足够频繁,会话将很快填满。

pxq42qpu

pxq42qpu4#

你可以只捕获响应头事件并删除'set-cookie'头:

app.use(function(req, res, next) {
  res.on('header', function () {
    if (req.headers.authorization) {
      delete res._headers['set-cookie'];
    }
  });
  next();
});

从技术上讲,您可以将其放在中间件链中的任何位置。

相关问题