使用 websockets 和 Nest.js 的 Passport 会话身份验证未进行身份验证

Posted

技术标签:

【中文标题】使用 websockets 和 Nest.js 的 Passport 会话身份验证未进行身份验证【英文标题】:Passport session authentication with websockets and Nest.js not authenticating 【发布时间】:2021-10-11 12:24:07 【问题描述】:

我无法使用 socket.io 和 nest.js 获得会话身份验证。在常规请求中,会话警卫工作得很好。适配器本身似乎工作。控制台没有显示错误,只是没有进行身份验证。

main.ts

async function bootstrap() 
  const app = await NestFactory.create(AppModule);
  const configService = app.get(ConfigService);
  const sessionSecret = configService.get('SESSION_SECRET');
  const MongoUri = configService.get('MONGO_URI');
  const sessionMiddleware = session(
    secret: sessionSecret,
    resave: false,
    saveUninitialized: false,
    store: MongoStore.create( mongoUrl: MongoUri ),
    cookie: 
      maxAge: 60 * 1000 * 60 * 24 * 14,
    ,
  );
  app.enableCors(
    origin: 'http://localhost:4200',
    credentials: true,
  );
  app.use(sessionMiddleware);
  app.use(passport.initialize());
  app.use(passport.session());
  app.use(cookieParser());
  app.useWebSocketAdapter(new SessionAdapter(sessionMiddleware));
  await app.listen(3000);

bootstrap();

会话适配器

export class SessionAdapter extends IoAdapter 
  private session: express.RequestHandler;

  constructor(session: express.RequestHandler) 
    super(session);
    this.session = session;
  

  create(port: number, options?: ServerOptions): Server 
    const server: Server = super.create(port, options);

    const wrap = (middleware) => (socket, next) =>
      middleware(socket.request, , next);

    server.use((socket, next) => 
      socket.data.username = 'test'; //passing random property to see if use method is working
      next();
    );
    server.use(wrap(this.session));
    server.use(wrap(passport.initialize()));
    server.use(wrap(passport.session()));
    return server;
  

Event.gateway.ts

@WebSocketGateway(80, 
  cors: 
    origin: 'http://localhost:4200',
  ,
)
export class EventsGateway implements OnGatewayConnection 
  @WebSocketServer()
  server: Server;

  // @UseGuards(AuthenticatedGuard)
  @UseGuards(WsAuthenticatedGuard)
  @SubscribeMessage('message')
  handleMessage(client: any, payload: any): string 
    console.log(payload);
    console.log(client.username);
    console.log(client.request.user);
    client.emit('answer', 'Hello client');
    return payload;
  

  handleConnection(client: any, ...args: any[]) 
    console.log(client.data.username); //console is showing 'test' as it suppose to
    console.log('user connected');
  

ws.authenticated.guard.ts

@Injectable()
export class WsAuthenticatedGuard implements CanActivate 
  async canActivate(context: ExecutionContext) 
    const client = context.switchToWs().getClient();
    const request = client.request;
    console.log(request.isAuthenticated());
    return request.isAuthenticated(); //guard returns false
  

authenticated.guard.ts(常规请求的保护)

@Injectable()
export class AuthenticatedGuard implements CanActivate 
  async canActivate(context: ExecutionContext) 
    const request = context.switchToHttp().getRequest();
    return request.isAuthenticated();
  

控制台记录的请求显示会话和护照已初始化,但没有来自 passport.session() 的用户属性

sessionID: 'Mu7DiHk_eNZ4S-ujFhnXOOqOl7EwLLFe',
  session: Session 
    cookie: 
      path: '/',
      _expires: 2021-08-21T15:53:24.871Z,
      originalMaxAge: 1209600000,
      httpOnly: true
    
  ,
  _passport: 
    instance: Authenticator 
      _key: 'passport',
      _strategies: [Object],
      _serializers: [Array],
      _deserializers: [Array],
      _infoTransformers: [],
      _framework: [Object],
      _userProperty: 'user',
      _sm: [SessionManager],
      Authenticator: [Function: Authenticator],
      Passport: [Function: Authenticator],
      Strategy: [Function],
      strategies: [Object]
    

【问题讨论】:

【参考方案1】:

看来您必须将app 传递给IoAdapter 的构造函数:

constructor(session: express.RequestHandler, app: INestApplicationContext) 
  super(app);
  this.session = session;

并按如下方式初始化适配器:

app.useWebSocketAdapter(new SessionAdapter(sessionMiddleware));

至少在我的情况下,这是缺少的部分。

【讨论】:

以上是关于使用 websockets 和 Nest.js 的 Passport 会话身份验证未进行身份验证的主要内容,如果未能解决你的问题,请参考以下文章

Nest.js WebSocket

nest.js + typeORM:基本使用

Nest.JS 和 Observables

无法连接到数据库 - NEST.JS 和 TypeORM

使用 Dapr JS SDK 让 Nest.js 集成 Dapr

Nest.js 与 AWS Cognito,如何访问用户属性