Я использую Apollo Server 2 (но эта проблема не только с Аполлоном) и Express.js vanilla (с apollo-server-express).
Все хорошо работает и с Подписки, кроме механизма Экспресс-сессия.
Эта проблема:
Я использую cookie-сессия (https://github.com/expressjs/cookie-session, но я думаю, что это то же самое для промежуточного программного обеспечения экспресс-сессия), и когда мой браузер запускает новое соединение с моим сервером, хук ApolloServer onConnect не имеет атрибута req, ни req.session и так далее ...
Что я могу сделать, так это проанализировать файлы cookie из webSocket.upgradeReq.headers.cookie в ловушке жизненного цикла onConnect, но мне это кажется очень хакерским.
Код:
const { ApolloServer } = require('apollo-server-express')
const typeDefs = require('../src/graphql/types')
const resolvers = require('../src/graphql/resolvers')
const models = require('../src/models')
const apolloServer = new ApolloServer({
typeDefs,
resolvers,
context: ({ req, connection }) => {
// connection exists only on webSocket connection
if (connection) {
return {
currentUser: connection.context.currentUser // <-- I NEED THIS!
}
}
// if not a (webSocket) connection it is a "default" HTTP call
return {
models,
currentUser: { id: req.user.id }
}
},
subscriptions: {
onConnect: (connectionParams, webSocket) => {
// "connectionParams" is from the client but I cannot use it because cookies are HTTP-Only
// I can retrieve cookies from here: "webSocket.upgradeReq.headers.cookie" but then I need to parse them which seems a bit hacky to me
// return { currentUser: req.user.id } // <-- I NEED THIS (req.user.id doesn't exists)!
}
}
})
module.exports = apolloServer
Я не могу найти ничего на сайте Apollo Server Docs (другие темы очень хорошо документированы!).
Где я делаю не так?





См. Этот комментарий: https://github.com/expressjs/cookie-session/issues/117#issuecomment-452046225 от dougwilson, чтобы получить значения сеанса.
If you just want to get the session contents (and not write back a new session -- which would not be possible without a res anyhow), you could likely just use the cookies module directly, which is what this module uses under the hood to read the cookie and validate the signature. A possible example:
const Cookies = require('cookies') // … const cookies = new Cookies(req, null, { keys }) const session = JSON.parse(Buffer.from(cookies.get('session'),'base64').toString('utf8'))
И onConnect вернет все, что вам нужно, на subscribe ()
Похоже, это предполагает, что вы можете передать необходимые данные cookie на стороне клиента для получения в контексте на сервере.
Передайте параметры для подключения к веб-сокету: https://www.apollographql.com/docs/react/advanced/subscriptions.html#authentication
Это то, что ! использовать
//Session middleware before resolvers
const sessionParser = session({
store,
secret: config.get('keys.session_secret'),
//...The rest config here
}
});
const apolloServer = new ApolloServer({
schema,
context: ({req, res, connection}: TheContext): TheContext => {
return {req, res, redisStore: store, connection}; //connection is must here
},
subscriptions: {
onConnect: (_params, _ws, ctx) => {
return new Promise((resolve, reject) => {
const req = ctx.request as express.Request;
const res = ({} as any) as express.Response;
//Parsing session
sessionParser(req, res, (_: any) => {
const session = req.session as any;
//Getting userId which was stored during login
const userId = session.userId;
if (!userId) {
reject(new AppError('You are not logged in'));
}
//This will be available in subscription via connection as
//something.connection.context.userId
resolve({userId});
});
});
}
}
});
И я использую с ТипGraphql вот так
@Subscription(() => Post, {
topics: ({context}) => `${Topic.DELETED_POST}:${parseUserId(context)}`,
description: 'To be used in requests list and not for individual request'
})
deletedPost(@Root() post: Post) {
return post;
}
Вот как я получаю доступ к userId, который был сохранен в сеансе
export function parseUserId(obj: any): string {
return obj.connection.context.userId ?? '';
}
Кредит на все ответы здесь
как ты это решил?