我正在使用Apollo Server 2(,但这个问题不仅是Apollo )和Express.js vanilla(带有apollo-server-express
)。
除快速会话机制外,订阅也都可以正常工作。
问题:
我正在使用 cookie-session (https://github.com/expressjs/cookie-session,但是我认为 express-session 中间件是一样的),并且当我的浏览器启动与服务器的新连接,ApolloServer onConnect
钩子没有req
属性,也没有req.session
等……
我能做的是在webSocket.upgradeReq.headers.cookie
生命周期钩子中解析来自onConnect
的cookie,但是在我看来,这很hacky。
代码:
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网站上找不到任何东西(对于其他文献记录非常丰富!)。
我在哪里做错了?
答案 0 :(得分:1)
答案 1 :(得分:1)
这是什么!使用
//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});
});
});
}
}
});
我像这样使用 TypeGraphql
@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 ?? '';
}
感谢所有答案here
答案 2 :(得分:0)
请参阅以下评论:dougwilson的https://github.com/expressjs/cookie-session/issues/117#issuecomment-452046225以获取会话值。
如果您只想获取会话内容(而不写回新会话-如果没有res就无法实现),则可能直接使用cookies模块,该模块在以下模块中使用读取cookie并验证签名的引擎盖。一个可能的例子:
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()上使用的任何内容
答案 3 :(得分:0)
这似乎建议您可以在客户端传递所需的cookie数据,以在服务器上的上下文中接收。
传入用于websocket连接的参数:https://www.apollographql.com/docs/react/advanced/subscriptions.html#authentication