问题
I'm using a passport local strategy that works well with express:
passport.use(localStrategy);
passport.serializeUser((user, done) => done(null, JSON.stringify(user)));
passport.deserializeUser((obj, done) => done(null, JSON.parse(obj)));
app.use(passport.initialize());
app.use(passport.session());
This localStrategy is doing a Mongoose call to get the user based on his pubKey and I guess that request.user is populated by this way.
I setup my graphql endpoint like this:
app.use('/graphql', bodyParser.json(), graphqlExpress(request => ({
debug: true,
schema,
context: {
user: request.user,
req: request,
},
formatError: (e) => {
console.log(JSON.stringify(e, null, 2));
return e;
},
})));
And my subscriptions this way:
const ws = createServer(app);
// Run the server
ws.listen(settings.APP_PORT, () => {
console.log(`App listening on port ${settings.APP_PORT}!`);
// Set up the WebSocket for handling GraphQL subscriptions
new SubscriptionServer({
execute,
subscribe,
schema,
onConnect: (connectionParams, webSocket) => {
console.log(webSocket.upgradeReq);
return { user: connectionParams };
},
}, {
server: ws,
path: '/subscriptions',
});
});
My session is working well on graphql queries and mutations. But not with my subscriptions.
My goal is to have access to my user session in my subscription resolver context. I may need to access something like request.user in onConnect to populate the context, but I don't know how to do.
回答1:
So after some tinkering I've figured out that what you need to do is basically run the everything that recreates the passport
for the socket's upgradeReq
by re-running the middleware:
// Start with storing the middleware in constants
const passportInit = passport.initialize();
const passportSession = passport.session();
app.use(passportInit);
app.use(passportSession);
...
// Now populate the request with the upgradeReq using those constants
onConnect: (connectionParams, webSocket) => new Promise((resolve) => {
passportInit(webSocket.upgradeReq, {}, () => {
passportSession(webSocket.upgradeReq, {}, () => {
resolve(webSocket.upgradeReq);
});
});
}),
If you are using an express-session
you need to add that to the above.
来源:https://stackoverflow.com/questions/47526793/how-to-use-subscriptions-transport-ws-with-passport-and-express-session