Authentication Apollo订阅JWT身份验证

Authentication Apollo订阅JWT身份验证,authentication,jwt,apollo,apollo-client,apollo-server,Authentication,Jwt,Apollo,Apollo Client,Apollo Server,我正在使用Robin Wieruch的fullstack样板文件,但它缺少订阅的身份验证。它在会话中使用JWT令牌,在http中工作正常,但在ws-auth中完全缺失 我还需要通过订阅的用户上下文,我需要订阅解析程序中的会话信息来决定是否应该启动订阅 我确实搜索了Apollo文档,我看到我应该使用onConnect:{ const-token=req.headers['x-token']; 如果(令牌){ 试一试{ return wait jwt.verify(token、process.env

我正在使用Robin Wieruch的fullstack样板文件,但它缺少订阅的身份验证。它在会话中使用JWT令牌,在http中工作正常,但在ws-auth中完全缺失

我还需要通过订阅的用户上下文,我需要订阅解析程序中的会话信息来决定是否应该启动订阅

我确实搜索了Apollo文档,我看到我应该使用
onConnect:
函数,但是没有完全功能的fullstack示例,我不确定如何从客户端传递JWT以便能够在webSocket对象中获得它

以下是我到目前为止的情况:

服务器:

从“express”导入express;
进口{
阿波罗服务器,
身份验证错误,
}来自“阿波罗服务器快车”;
常量app=express();
应用程序使用(cors());
const getMe=async req=>{
const-token=req.headers['x-token'];
如果(令牌){
试一试{
return wait jwt.verify(token、process.env.SECRET);
}捕获(e){
抛出新的身份验证错误(
“您的会话已过期。请重新登录。”,
);
}
}
};
const server=新服务器({
反省:没错,
typeDefs:schema,
解析器,
订阅:{
onConnect:(connectionParams、webSocket、context)=>{
console.log(webSocket);
},
},
上下文:异步({req,connection})=>{
//订阅
如果(连接){
返回{
//怎么在这里也超过我?
模型,
};
}
//突变和查询
如果(请求){
const me=等待getMe(请求);
返回{
模型,
我
秘密:process.env.secret,
};
}
},
});
applyMiddleware({app,路径:'/graphql'});
const httpServer=http.createServer(app);
installSubscriptionHandlers(httpServer);
常量isTest=!!process.env.TEST_数据库_URL;
const isProduction=process.env.NODE_env==“production”;
const port=process.env.port | 8000;
httpServer.listen({port},()=>{
console.log(`Apollo Server onhttp://localhost:${port}/graphql`);
});
客户:


const httpLink=createUploadLink({
uri:'http://localhost:8000/graphql',
fetch:customFetch,
});
const wsLink=新的WebSocketLink({
uri:`ws://localhost:8000/graphql`,
选项:{
对,,
},
});
常数终止链接=拆分(
({query})=>{
const{kind,operation}=getMainDefinition(查询);
返回(
种类=='OperationDefinition'&&operation=='subscription'
);
},
wsLink,
httpLink,
);
const authLink=新链接((操作,转发)=>{
operation.setContext(({headers={}})=>{
const token=localStorage.getItem('token');
如果(令牌){
headers={…headers,'x-token':token};
}
返回{headers};
});
返回向前(操作);
});
const errorLink=onError({graphQLErrors,networkError})=>{
如果(图形错误){
forEach({message,locations,path})=>{
log('GraphQL错误',消息);
如果(消息==“未经验证”){
签出(客户);
}
});
}
如果(网络错误){
console.log('networkError',networkError);
if(networkError.statusCode==401){
签出(客户);
}
}
});
const-link=ApolloLink.from([authLink,errorLink,terminatingLink]);
常量缓存=新的InMemoryCache();
const客户端=新客户端({
链接
隐藏物
解析器,
typeDefs,
});
您需要使用从客户端设置JWT。下面是使用angular框架的代码片段:

const WS_URI=`wss://${environment.HOST}:${environment.PORT}${
environment.WS_路径
}`;
const wsClient=subscriptionService.getWSClient(WS_URI{
懒惰:是的,
//如果connectionParams是一个函数,则在每次连接之前对其求值。
connectionParams:()=>{
返回{
令牌:`Bearer${authService.getJwt()}`
};
},
对,,
重新连接尝试:5次,
connectionCallback:(错误:错误[])=>{
如果(错误){
console.log(错误);
}
log('connectionCallback');
},
不活动时间:1000
});
const wsLink=新的WebSocketLink(wsClient);
在服务器端,使用
onConnect
事件处理程序处理JWT是正确的。例如

const server=新服务器({
typeDefs,
解析器,
context:contextFunction,
反省:没错,
订阅:{
onConnect:(
connectionParams:IWebSocketConnectionParams,
webSocket:webSocket,
connectionContext:connectionContext,
) => {
log('websocketconnect');
log('connectionParams:',connectionParams);
if(connectionParams.token){
const token:string=validateToken(connectionParams.token);
const userConnector=新的userConnector(memoryDB);
let user:IUser |未定义;
试一试{
const userType:userType=userType[token];
user=userConnector.finduserbyuser类型(userType);
}捕获(错误){
投掷误差;
}
常量上下文:ISubscriptionContext={
//pubsub:postgresPubSub,
pubsub,
订阅用户:用户,
用户连接器,
位置连接器:新的位置连接器(memoryDB),
};
返回上下文;
}
抛出新错误('缺少身份验证令牌!');
},
onDisconnect:(webSocket:webSocket,connectionContext:connectionContext)=>{
log('websocketdisconnect');
},
},
});
服务器端:


客户端:

我这样做了,我从websocket和http获得了不同的令牌?我从websockets中的上一个会话中获得过时的令牌。你知道为什么会发生这种情况以及如何清除吗