使用 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 会话身份验证未进行身份验证的主要内容,如果未能解决你的问题,请参考以下文章