为什么我的自定义Redis会话存储中的set方法被触发两次?

问题描述 投票:0回答:1

我正在使用 NestJS、Passport、express-session 开发一个 Web 应用程序,并且我已经使用 Redis (ioredis) 实现了自定义会话管理。我注意到,对于单个用户会话创建,我的自定义 RedisStore 中的 set 方法被触发两次,我无法弄清楚为什么会发生这种情况。所有其他方法仅触发一次。

我有一个 LocalAuthGuard,它从 @nestjs/passport 扩展了 AuthGuard('local'),用于身份验证:

import { ExecutionContext, Injectable } from '@nestjs/common';
import { AuthGuard } from '@nestjs/passport';

@Injectable()
export class LocalAuthGuard extends AuthGuard('local') {
  async canActivate(context: ExecutionContext) {
    const result = (await super.canActivate(context)) as boolean;
    const request = context.switchToHttp().getRequest();

    await super.logIn(request);
    return result;
  }
}

我的会话在引导函数中配置如下:

app.use(
    session({
      name: 'dekada_session',
      store: new RedisStore(redisService),
      secret: 'keyboard cat',
      resave: false,
      saveUninitialized: false,
      rolling: false,
      cookie: {
        maxAge: 3600000,
        secure: false,
        sameSite: 'lax',
        httpOnly: true,
      },
    }),
  );

这是set的简化版本

set(sid: string, session: SessionData, callback?: (error?: any) => void): void {
  console.log('set');
  const ttl = 3600;
  this.redisService.getClient().setex(`sess:${sid}`, ttl, JSON.stringify(session), (error) => {
    callback(error);
  });
}

尽管 Postman 只发送了一个请求,但 set 方法被记录了两次,表明它被调用了两次。这种情况发生在登录过程中,其中会话应该只创建一次。我验证了 Passport 的 serializeUser 和 deserializeUser 方法只调用了一次,我的 LocalAuthGuard 中的 canActivate 方法也是如此。

这就是控制台日志的触发方式:

  1. 得到
  2. 摧毁
  3. 设置
  4. 【功能:连载】
  5. 设置
nestjs passport.js express-session
1个回答
0
投票

检查护照码后,找到双集调用的根源。

/lib/sessionmanager.js

SessionManager.prototype.logIn = function(req, user, options, cb) {
  if (typeof options == 'function') {
    cb = options;
    options = {};
  }
  options = options || {};
  
  if (!req.session) { return cb(new Error('Login sessions require session support. Did you forget to use `express-session` middleware?')); }
  
  var self = this;
  var prevSession = req.session;
  
  // regenerate the session, which is good practice to help
  // guard against forms of session fixation
  req.session.regenerate(function(err) {
    if (err) {
      return cb(err);
    }
    
    self._serializeUser(user, req, function(err, obj) {
      if (err) {
        return cb(err);
      }
      if (options.keepSessionInfo) {
        merge(req.session, prevSession);
      }
      if (!req.session[self._key]) {
        req.session[self._key] = {};
      }
      // store user information in session, typically a user id
      req.session[self._key].user = obj;
      // save the session before redirection to ensure page
      // load does not happen before session is saved
      req.session.save(function(err) {
        if (err) {
          return cb(err);
        }
        cb();
      });
    });
  });
}

此代码通过在保留会话数据的同时创建新的会话 ID 来重新生成会话,作为抵御会话固定攻击的安全措施。重新生成后,它会再次显式保存会话。然而,express-session 似乎注意到了会话更新,并在请求-响应周期结束时自动触发另一个设置操作。

虽然我了解出于安全目的而重新生成会话的必要性,但我希望通过消除快速会话进行的冗余设置调用来优化会话处理。这种冗余似乎没有必要,并且可能会影响性能。

问题:有没有办法配置express-session或Passport来防止这种额外的会话集操作,同时仍然保持会话的完整性和安全性,特别是在防止会话固定攻击的情况下?

© www.soinside.com 2019 - 2024. All rights reserved.